每次调用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;
[1]: http://jsfiddle.net/fp2tncmb/2/
答案 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;:
虚拟DOM渲染:当调用渲染方法时,它返回组件的新虚拟dom 结构。正如我之前提到的,当您调用 setState()时,总会调用此 render 方法,因为 shouldComponentUpdate 默认情况下始终返回true。因此,默认情况下,React中没有优化。
原生DOM渲染:只有在虚拟DOM中根据需要更改它们时,React才会更改浏览器中的真实DOM节点 - 这就是React的优秀功能,它可以优化真正的DOM突变并使其成为可能快速反应。
答案 1 :(得分:88)
不,当状态发生变化时,React不会渲染所有内容。
每当组件变脏(其状态发生变化)时,该组件及其子组件将被重新呈现。在某种程度上,这是尽可能少地重新渲染。渲染不被调用的唯一时间是将某个分支移动到另一个分支,理论上我们不需要重新渲染任何东西。在您的示例中,TimeInChild
是Main
的子组件,因此当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钩子似乎不再是公认的答案。您可以在此代码沙箱中看到,当状态设置为相同的值时,将重新渲染类组件,而在功能组件中,将状态设置为相同的值不会导致重新渲染。
答案 6 :(得分:0)
不是所有组件。
组件中的state
看起来像整个APP的状态瀑布之源。
因此更改发生在setState调用的位置。 renders
树然后从那里被调用。如果您使用的是纯组分,则render
将被跳过。