ReactJS - 在调用“setState”的任何时候都会调用render吗?

时间:2014-07-13 01:11:08

标签: javascript reactjs

每次调用setState时,React是否重新渲染所有组件和子组件?

如果是这样,为什么?我认为这个想法是React只在需要的时候渲染 - 当状态改变时。

在下面的简单示例中,两个类在单击文本时再次呈现,尽管状态在后续点击时没有变化,因为onClick处理程序始终将state设置为相同值:

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

我希望只有在state数据发生变化时才能进行渲染。

以下是示例代码as a 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);
&#13;
<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>
&#13;
&#13;
&#13;

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

7 个答案:

答案 0 :(得分:464)

  

每次调用setState时,React都会重新渲染所有组件和子组件吗?

默认情况下 - 是。

有一个方法 boolean shouldComponentUpdate(object nextProps,object nextState),每个组件都有这个方法,它负责确定&#34;组件应该更新(运行渲染功能)?&#34;每次更改 state 或从父组件传递新的 props 时。

您可以为组件编写自己的 shouldComponentUpdate 方法实现,但默认实现始终返回true - 意味着始终重新运行render函数。

引自官方文档http://facebook.github.io/react/docs/component-specs.html#updating-shouldcomponentupdate

  

默认情况下,shouldComponentUpdate始终返回true以防止   当状态发生变异时会出现微妙的错误,但是如果你小心的话   总是将状态视为不可变状态,只能从道具和状态中读取   在render()中,你可以用一个覆盖shouldComponentUpdate   将旧道具和状态与他们的状态进行比较的实现   替代品。

问题的下一部分:

  

如果是这样,为什么?我认为这个想法是React只在需要的时候渲染 - 当状态改变时。

我们可以调用两个步骤&#34;渲染&#34;:

  1. 虚拟DOM渲染:当调用渲染方法时,它返回组件的新虚拟dom 结构。正如我之前提到的,当您调用 setState()时,总会调用此 render 方法,因为 shouldComponentUpdate 默认情况下始终返回true。因此,默认情况下,React中没有优化。

  2. 原生DOM渲染:只有在虚拟DOM中根据需要更改它们时,React才会更改浏览器中的真实DOM节点 - 这就是React的优秀功能,它可以优化真正的DOM突变并使其成为可能快速反应。

答案 1 :(得分:88)

不,当状态发生变化时,React不会渲染所有内容。

  • 每当组件变脏(其状态发生变化)时,该组件及其子组件将被重新呈现。在某种程度上,这是尽可能少地重新渲染。渲染不被调用的唯一时间是将某个分支移动到另一个分支,理论上我们不需要重新渲染任何东西。在您的示例中,TimeInChildMain的子组件,因此当Main的状态发生更改时,它也会重新呈现。

  • React不会比较状态数据。调用setState时,它会将组件标记为脏(这意味着需要重新呈现)。需要注意的重要一点是,尽管调用了组件的render方法,但只有当输出与当前DOM树不同时才更新真正的DOM(也就是虚拟DOM树和文档之间的差异) DOM树)。在您的示例中,即使state数据没有更改,上次更改的时间也会发生,使Virtual DOM与文档的DOM不同,因此HTML更新的原因。

答案 2 :(得分:3)

是的。每当“ shouldComponentUpdate”返回false时,它将每次调用setState时调用render()方法。

答案 3 :(得分:3)

“丢失更新”的另一个原因可能是下一个:

如果是问题,那么U可以避免在更新过程中设置状态,您应该像这样检查状态参数值

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

另一种解决方案是在状态中添加一个初始化的属性,并在第一次设置(如果状态被初始化为非null值)。

答案 4 :(得分:1)

即使在这里的许多其他答案中都已说明,该组件也应该:

  • 实现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>

答案 5 :(得分:1)

使用React钩子似乎不再是公认的答案。您可以在此代码沙箱中看到,当状态设置为相同的值时,将重新渲染类组件,而在功能组件中,将状态设置为相同的值不会导致重新渲染。

https://codesandbox.io/s/still-wave-wouk2?file=/src/App.js

答案 6 :(得分:0)

不是所有组件。

组件中的state看起来像整个APP的状态瀑布之源。

因此更改发生在setState调用的位置。 renders树然后从那里被调用。如果您使用的是纯组分,则render将被跳过。