ReactJS- "setState"가 호출 될 때마다 렌더링이 호출됩니까?


503

React setState는 호출 될 때마다 모든 구성 요소 및 하위 구성 요소를 다시 렌더링합니까 ?

그렇다면 왜 그렇습니까? React는 상태가 변경 될 때 React가 필요한만큼만 렌더링한다는 생각을했습니다.

다음 간단한 예제에서 onClick 핸들러는 항상 state같은 값으로 설정하므로 후속 클릭에서 상태가 변경되지 않더라도 텍스트를 클릭하면 두 클래스가 다시 렌더링됩니다 .

this.setState({'test':'me'});

state데이터가 변경된 경우에만 렌더링이 발생할 것으로 예상했습니다 .

다음 은 JS Fiddle 및 포함 된 스 니펫 인 예제 코드입니다.

var TimeInChild = React.createClass({
    render: function() {
        var t = new Date().getTime();

        return (
            <p>Time in child:{t}</p>
        );
    }
});

var Main = React.createClass({
    onTest: function() {
        this.setState({'test':'me'});
    },

    render: function() {
        var currentTime = new Date().getTime();

        return (
            <div onClick={this.onTest}>
            <p>Time in main:{currentTime}</p>
            <p>Click me to update time</p>
            <TimeInChild/>
            </div>
        );
    }
});

ReactDOM.render(<Main/>, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react-dom.min.js"></script>

[1]: http://jsfiddle.net/fp2tncmb/2/

나는 똑같은 문제를 겪었고 정확한 해결책을 모른다. 그러나 평소처럼 작동하기 시작한 구성 요소에서 원하지 않는 코드를 정리했습니다.
제이슨

귀하의 예제에서 요소를 디자인하는 방법은 고유 한 상태에만 의존하지 않기 때문에 setState()더미 데이터로 호출 해도 요소가 다르게 렌더링되므로 예라고 대답하고 싶습니다. 당연히 무언가가 변경되었을 때 객체를 다시 렌더링하려고 시도해야합니다. 그렇지 않으면 데모가 의도 된 동작이라고 가정하면 작동하지 않기 때문입니다!
Tadhg McDonald-Jensen

당신은 맞습니다 @ TadhgMcDonald-Jensen-그러나 내 이해에 따르면, React는 처음으로 (상태가 처음부터 다른 것으로 바뀌기 때문에) 처음으로 렌더링 한 다음 다시 렌더링 할 필요가 없었습니다. 물론 React는 자신의 shouldComponentUpdate메소드 를 작성 해야하는 것처럼 보였으 므로 간단한 버전이 이미 React 자체에 포함되어 있다고 가정했습니다. 반응에 포함 된 기본 버전과 같은 소리는 단순히 반환 true합니다. 구성 요소는 매번 다시 렌더링됩니다.
Brad Parks

예. 그러나 가상 DOM에서만 다시 렌더링하면됩니다. 구성 요소가 다르게 렌더링되는 경우 실제 DOM 만 변경됩니다. 가상 DOM에 대한 업데이트는 일반적으로 무시할 만하 며 (적어도 실제 화면에서 수정하는 것과 비교할 때) 무시할 수있을 때마다 렌더링을 호출 한 다음 업데이트가 필요할 때마다 렌더링을 호출하면 동일한 렌더링을 가정하는 것보다 비용이 많이 들고 안전하지 않은지 확인합니다.
Tadhg McDonald-Jensen

답변:


570

React는 setState가 호출 될 때마다 모든 구성 요소 및 하위 구성 요소를 다시 렌더링합니까?

기본적으로-예.

이 방법이다 shouldComponentUpdate 부울 (개체 nextProps, 객체 nextState) , 각 구성 요소는이 방법을 가지고는 그것을 결정하는 책임이 "구성 요소 업데이트 (실행이되어야 렌더링 기능)?" 상태 를 변경 하거나 부모 구성 요소에서 새 소품 을 전달할 때마다 .

구성 요소에 대해 shouldComponentUpdate 메서드를 직접 구현할 수 있지만 기본 구현은 항상 true를 반환합니다. 즉, 항상 렌더링 함수를 다시 실행합니다.

공식 문서에서 인용 http://facebook.github.io/react/docs/component-specs.html#updating-shouldcomponentupdate

기본적으로 shouldComponentUpdate는 상태가 변경 될 때 미묘한 버그를 방지하기 위해 항상 true를 반환하지만, 상태를 항상 변경할 수없는 것으로 취급하고 render ()의 props 및 state에서 읽기 전용으로주의해야하는 경우 shouldComponentUpdate를 기존 소품과 상태를 대체품과 비교하는 구현입니다.

질문의 다음 부분 :

그렇다면 왜 그렇습니까? 나는 아이디어가 상태가 변했을 때 React가 필요한만큼만 렌더링한다고 생각했습니다.

"렌더링"이라고하는 두 단계가 있습니다.

  1. 가상 DOM 렌더 : render 메소드가 호출 되면 컴포넌트 의 새로운 가상 dom 구조를 리턴합니다 . 앞에서 언급했듯이,이 렌더링 메소드는 setState () 를 호출 할 때 항상 호출 됩니다. shouldComponentUpdate 는 기본적으로 항상 true를 반환 하기 때문 입니다. 따라서 기본적으로 React에는 최적화가 없습니다.

  2. Native DOM 렌더 : React는 Virtual DOM에서 변경된 경우에만 브라우저에서 실제 DOM 노드를 변경하고 필요한만큼만 변경합니다. 이는 실제 DOM 돌연변이를 최적화하고 React를 빠르게 만드는 뛰어난 React 기능입니다.


47
좋은 설명! 이 경우 React가 실제로 빛을 발하게하는 한 가지는 가상 DOM이 변경되지 않는 한 실제 DOM을 변경하지 않는다는 것 입니다. 따라서 내 렌더링 함수가 동일한 것을 두 번 연속으로 반환하면 실제 DOM은 전혀 변경되지 않습니다 ... 고마워!
Brad Parks

1
@tungd 가 옳다고 생각합니다 -아래에서 그의 대답을보십시오. 또한 구성 요소 간 상위-하위 관계의 문제입니다. 예를 들어 TimeInChildMain 의 형제 이면 render () 가 불필요하게 호출되지 않습니다.
gvlax

2
상태에 비교적 큰 자바 스크립트 객체 (~ 1k 총 속성)가 포함되어 있는데, 이는 큰 컴포넌트 트리 (~ 100 총)로 렌더링됩니다. 상태에서 새 상태를 이전 상태와 수동으로 비교하고 setState차이가있는 경우 에만 호출 합니까? 그렇다면 어떻게해야합니까? Json 문자열을 비교하고 객체 해시를 구성하고 비교하십시오 ...?
Vincent Sels

1
@Petr이지만 반응이 가상 dom을 재구성하더라도 이전 가상 dom이 새로운 가상 dom과 동일하면 브라우저 dom이 손대지 않습니다.
Jaskey

3
또한 React.PureComponent ( reactjs.org/docs/react-api.html#reactpurecomponent ) 를 사용하십시오 . 구성 요소의 상태 또는 소품이 실제로 변경된 경우에만 업데이트 (렌더링)합니다. 그러나 비교가 얕다는 점에 유의하십시오.
토론자

105

아니요, React는 상태가 변경 될 때 모든 것을 렌더링하지 않습니다.

  • 구성 요소가 더럽거나 (상태가 변경 될 때마다) 해당 구성 요소와 해당 하위 구성 요소가 다시 렌더링됩니다. 이것은 어느 정도까지 가능한 한 적게 다시 렌더링하는 것입니다. 렌더가 호출되지 않는 유일한 시점은 일부 브랜치를 다른 루트로 옮길 때입니다. 이론적으로 우리는 아무것도 다시 렌더링 할 필요가 없습니다. 귀하의 예에서는 TimeInChild의 하위 구성 요소 Main이므로 Main변경 상태가되면 다시 렌더링됩니다 .

  • 반응은 상태 데이터를 비교하지 않습니다. setState호출 되면 구성 요소를 더티로 표시합니다 (즉, 다시 렌더링해야 함). 주목할 점은 render컴포넌트의 메소드가 호출되지만 실제 DOM은 출력이 현재 DOM 트리와 다른 경우에만 업데이트된다는 것입니다 (가상 DOM 트리와 문서의 DOM 트리 사이의 차이). 귀하의 예에서는 state데이터가 변경되지 않았 더라도 마지막 변경 시간이 변경되어 Virtual DOM이 문서의 DOM과 다르므로 HTML이 업데이트되는 이유가 있습니다.


네, 정답입니다. 실험으로 마지막 줄을 React.renderComponent (<div> <Main /> <TimeInChild /> </ div>, document.body)로 수정하십시오 . 제거 <TimeInChild /> 의 본체로부터 렌더링 ()주요 구성 요소. TimeInChildrender () 는 더 이상 Main 의 자식이 아니므로 기본적으로 호출되지 않습니다 .
gvlax

고마워, 이와 같은 것들이 약간 까다롭기 때문에 React 저자 render()는 외부 상태와 독립적으로 방법이 "순수"해야한다고 권장합니다 .
tungd

3
@ tungd, 무슨 뜻 some branch is moved to another root인가요? 뭐라고 불러 branch? 뭐라고 불러 root?
Green

2
나는 정답으로 표시된 답을 선호합니다. 나는 네이티브, '실제'면에서 '렌더링'에 대한 해석을 이해하지만 반응 네이티브 측면에서 보면 렌더링이 다시 렌더링된다고 말해야합니다. 운 좋게도 실제로 변경된 사항을 결정하고 이러한 사항 만 업데이트하는 것이 현명합니다. 이 답변은 새로운 사용자에게는 혼란 스러울 수 있습니다. 먼저 아니오라고 말한 다음 상황이 렌더링된다고 설명합니다.
WiRa

1
@ tungd 그린의 질문을 설명해 주시겠습니까?what does it mean some branch is moved to another root? What do you call branch? What do you call root?
madhu131313

7

여기에 다른 많은 답변에 언급되어 있지만 구성 요소는 다음 중 하나 여야합니다.

  • shouldComponentUpdate상태 또는 속성이 변경 될 때만 렌더링하도록 구현

  • 얕은 비교를 위해 이미 내부적 으로 메소드를 구현 하는 PureComponent 확장으로 전환하십시오 shouldComponentUpdate.

다음은 shouldComponentUpdate간단한 사용 사례 및 데모 목적으로 만 작동하는를 사용하는 예제입니다 . 이것을 사용하면 구성 요소는 더 이상 클릭 할 때마다 다시 렌더링되지 않으며 처음 표시 될 때와 한 번 클릭 한 후에 렌더링됩니다.

var TimeInChild = React.createClass({
    render: function() {
        var t = new Date().getTime();

        return (
            <p>Time in child:{t}</p>
        );
    }
});

var Main = React.createClass({
    onTest: function() {
        this.setState({'test':'me'});
    },

    shouldComponentUpdate: function(nextProps, nextState) {
      if (this.state == null)
        return true;
  
      if (this.state.test == nextState.test)
        return false;
        
      return true;
  },

    render: function() {
        var currentTime = new Date().getTime();

        return (
            <div onClick={this.onTest}>
            <p>Time in main:{currentTime}</p>
            <p>Click me to update time</p>
            <TimeInChild/>
            </div>
        );
    }
});

ReactDOM.render(<Main/>, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react-dom.min.js"></script>


6

예. "shouldComponentUpdate"가 false를 반환 할 때 setState를 호출 할 때마다 render () 메소드를 호출합니다.


7
좀 더 정교하십시오
Karthick Ramesh

3

"업데이트 손실"의 또 다른 이유는 다음과 같습니다.

  • 정적 getDerivedStateFromProps 가 정의 된 경우 공식 문서 https://reactjs.org/docs/react-component.html#updating 에 따라 모든 업데이트 프로세스에서 다시 실행됩니다 .
  • 따라서 상태 값이 처음에 props에서 나온 경우 모든 업데이트에서 덮어 씁니다.

그것이 문제라면 U는 업데이트하는 동안 상태를 설정하지 않아도되므로 상태 매개 변수 값을 다음과 같이 확인해야합니다

static getDerivedStateFromProps(props: TimeCorrectionProps, state: TimeCorrectionState): TimeCorrectionState {
   return state ? state : {disable: false, timeCorrection: props.timeCorrection};
}

또 다른 해결책은 초기화 된 속성을 state에 추가하고 처음에 설정합니다 (상태가 null이 아닌 값으로 초기화 된 경우).


0

모든 구성 요소가 아닙니다.

state성분에 보이는 전체 APP 상태의 폭포 소스처럼.

따라서 setState가 호출 된 위치에서 변경이 발생합니다. renders그때 의 나무가 거기에서 불러옵니다. 순수한 구성 요소를 사용한 경우 render건너 뜁니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.