ReactJS - 渲染是否在调用“setState”时被调用?

2022-08-29 22:39:16

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

如果是,为什么?我以为这个想法是 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

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

默认情况下 - 是的。

有一个方法布尔值 shouldComponentUpdate(object nextProps, object nextState),每个组件都有此方法,它负责确定每次更改状态或从父组件传递新道具时组件是否应更新(运行渲染函数)?”

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

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

默认情况下,shouldComponentUpdate 总是返回 true 以防止在状态就位时出现细微的错误,但是如果您小心地始终将状态视为不可变的,并且从 render() 中的 props 和 state 中只读,那么您可以使用将旧 props 和 state 与它们的替换进行比较的实现来覆盖 shouldComponentUpdate。

问题的下一部分:

如果是,为什么?我以为这个想法是 React 只在需要的时候渲染得尽可能少 - 当状态改变时。

我们可以称之为“渲染”的两个步骤:

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

  2. 原生 DOM 渲染:React 仅在虚拟 DOM 中更改了真正的 DOM 节点,并且根据需要尽可能少地更改了它们 ,React 才会更改它们 - 这是 React 的强大功能,它优化了真正的 DOM 突变并使 React 速度很快。


答案 2

不,React 不会在状态更改时呈现所有内容。

  • 每当组件变脏(其状态已更改)时,该组件及其子组件都会重新呈现。在某种程度上,这是为了尽可能少地重新渲染。唯一不调用渲染的情况是将某个分支移动到另一个根,从理论上讲,我们不需要重新渲染任何内容。在您的示例中,是 的子组件,因此当状态更改时,它也会重新呈现。TimeInChildMainMain

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