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

如果有,为什么?我认为React的想法是只渲染需要的部分-当状态改变时。

在下面这个简单的例子中,当文本被点击时,这两个类都会再次呈现,尽管在随后的点击中状态不会改变,因为onClick处理程序总是将状态设置为相同的值:

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

我本以为只有在状态数据发生变化时才会发生渲染。

下面是这个例子的代码,作为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>


当前回答

当使用React钩子时,似乎接受的答案不再是这种情况(使用原始值,查看这个答案的详细信息)。您可以在这个代码沙箱中看到,当状态设置为相同的值时,类组件会重新呈现,而在函数组件中,将状态设置为相同的值不会导致重新呈现。

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

其他回答

只有在比较当前状态值和新状态值并且它们不同之后才能使用setState()。

当使用React钩子时,似乎接受的答案不再是这种情况(使用原始值,查看这个答案的详细信息)。您可以在这个代码沙箱中看到,当状态设置为相同的值时,类组件会重新呈现,而在函数组件中,将状态设置为相同的值不会导致重新呈现。

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

是的。它只在每次调用setState时调用render()方法,除非shouldComponentUpdate返回false。

不,React不会在状态改变时渲染所有内容。

Whenever a component is dirty (its state changed), that component and its children are re-rendered. This, to some extent, is to re-render as little as possible. The only time when render isn't called is when some branch is moved to another root, where theoretically we don't need to re-render anything. In your example, TimeInChild is a child component of Main, so it also gets re-rendered when the state of Main changes. React doesn't compare state data. When setState is called, it marks the component as dirty (which means it needs to be re-rendered). The important thing to note is that although render method of the component is called, the real DOM is only updated if the output is different from the current DOM tree (a.k.a diffing between the Virtual DOM tree and document's DOM tree). In your example, even though the state data hasn't changed, the time of last change did, making Virtual DOM different from the document's DOM, hence why the HTML is updated.

React 18及以上

从React 18开始,所有状态更新都是自动批处理的。通过这种方式,React将多个状态更新分组到一个单独的重新渲染中,以获得更好的性能。

所以当你更新状态时,React总是尝试在组更新中批处理这些更新,导致比setState调用更少的渲染。使用钩子时的行为是相同的。

你可以在React 18的自动批处理公告中阅读很长的解释。

React 17及以下

在React 17及以下版本中,只有React事件处理程序内部的更新是批处理的。由promise、setTimeout、本机事件处理程序或其他事件触发的更新在React中默认不批量处理。