我知道React可能会异步执行批处理状态更新以优化性能。因此,在调用之后,您将永远无法相信要更新的状态setState
。但是你可以信任的反应更新相同的顺序状态setState
被称为对
- 相同的组件?
- 不同的组件?
考虑在以下示例中单击按钮:
1.在以下情况下,是否有可能a为假而b为真:
class Container extends React.Component {
constructor(props) {
super(props);
this.state = { a: false, b: false };
}
render() {
return <Button onClick={this.handleClick}/>
}
handleClick = () => {
this.setState({ a: true });
this.setState({ b: true });
}
}
2.在以下情况下,是否有可能a为假而b为真:
class SuperContainer extends React.Component {
constructor(props) {
super(props);
this.state = { a: false };
}
render() {
return <Container setParentState={this.setState.bind(this)}/>
}
}
class Container extends React.Component {
constructor(props) {
super(props);
this.state = { b: false };
}
render() {
return <Button onClick={this.handleClick}/>
}
handleClick = () => {
this.props.setParentState({ a: true });
this.setState({ b: true });
}
}
请记住,这些是我用例的极端简化。我意识到我可以做不同的事情,例如在示例1中同时更新两个状态参数,以及在示例2中在对第一状态更新的回调中执行第二状态更新。但是,这不是我的问题,我只对React是否有明确定义的方式来执行这些状态更新感兴趣,仅此而已。
非常感谢文档支持的任何答案。
我在做React。
TLDR:
但是你可以相信React可以按照要求setState的顺序更新状态吗
- 相同的组件?
是。
- 不同的组件?
是。
该订单的更新总是尊重。是否在它们之间看到中间状态取决于您是否在批处理中。
当前(React 16和更早版本),默认情况下仅批处理React事件处理程序中的更新。有一个不稳定的API可以在极少数情况下在需要时强制在事件处理程序之外进行批处理。
在将来的版本中(可能是React 17及更高版本),React默认会批处理所有更新,因此您不必考虑这一点。与往常一样,我们将在React博客和发行说明中宣布对此所做的任何更改。
理解这一点的关键是,无论setState()
您在React事件处理程序中执行了多少个组件中的多少次调用,它们都将在事件结束时仅产生一次重新渲染。这对于大型应用程序性能良好至关重要的,因为如果Child
与Parent
每个呼叫setState()
处理click事件的时候,你不想再渲染Child
两次。
在您的两个示例中,setState()
调用都在React事件处理程序中进行。因此,它们总是在事件结束时一起刷新(并且您看不到中间状态)。
更新总是按照发生的顺序进行浅层合并。因此,如果第一个更新为{a: 10}
,第二个为{b: 20}
,第三个为{a: 30}
,则渲染状态将为{a: 30, b: 20}
。对相同状态键的更新(例如,a
在我的示例中)总是“获胜”。
this.state
当我们在批处理结束时重新呈现UI时,将更新该对象。因此,如果您需要基于先前的状态(例如增加计数器)来更新状态,则应使用setState(fn)
为您提供先前状态的功能版本,而不是从中读取this.state
。如果您对此原因感到好奇,我会在此评论中对其进行深入解释。
在您的示例中,我们看不到“中间状态”,因为我们位于启用了批处理的React事件处理程序中(因为退出事件时React知道)。
但是,在React 16和早期版本中,默认情况下,在React事件处理程序外部都没有批处理。因此,如果在您的示例中使用AJAX响应处理程序代替handleClick
,则每个处理程序setState()
都会在发生时立即进行处理。在这种情况下,是的,您会看到一个中间状态:
promise.then(() => {
// We're not in an event handler, so these are flushed separately.
this.setState({a: true}); // Re-renders with {a: true, b: false }
this.setState({b: true}); // Re-renders with {a: true, b: true }
this.props.setParentState(); // Re-renders the parent
});
我们意识到,根据您是否在事件处理程序中,行为会有所不同,这很不方便。这将在以后的React版本中更改,该版本默认情况下将批处理所有更新(并提供选择加入的API以同步刷新更改)。在我们切换默认行为(可能在React 17中)之前,有一个可用于强制批处理的API:
promise.then(() => {
// Forces batching
ReactDOM.unstable_batchedUpdates(() => {
this.setState({a: true}); // Doesn't re-render yet
this.setState({b: true}); // Doesn't re-render yet
this.props.setParentState(); // Doesn't re-render yet
});
// When we exit unstable_batchedUpdates, re-renders once
});
内部所有React事件处理程序都被包装,unstable_batchedUpdates
这就是为什么默认情况下对它们进行批处理。请注意,将更新打包unstable_batchedUpdates
两次是无效的。当我们退出最外部的unstable_batchedUpdates
调用时,将刷新更新。
该API是“不稳定的”,即默认情况下启用批处理后我们将其删除。但是,我们不会在次要版本中删除它,因此在某些情况下,如果需要在React事件处理程序之外强制进行批处理,则可以放心使用它直到React 17。
总而言之,这是一个令人困惑的话题,因为默认情况下,React仅在事件处理程序内部进行批处理。这将在将来的版本中更改,并且行为将变得更加简单。但是解决方案不是少批处理,而是默认情况下多批处理。那就是我们要做的。
这实际上是一个非常有趣的问题,但答案应该不会太复杂。在媒体上有一篇很棒的文章有答案。
1)如果您这样做
this.setState({ a: true });
this.setState({ b: true });
我不认为会出现的情况下a
会true
和b
会false
因为配料。
但是,如果b
依赖于,a
则确实可能存在无法获得预期状态的情况。
// assuming this.state = { value: 0 };
this.setState({ value: this.state.value + 1});
this.setState({ value: this.state.value + 1});
this.setState({ value: this.state.value + 1});
处理完上述所有调用后,this.state.value
将为1,而不是您期望的3。
这是在文章中提到的: setState accepts a function as its parameter
// assuming this.state = { value: 0 };
this.setState((state) => ({ value: state.value + 1}));
this.setState((state) => ({ value: state.value + 1}));
this.setState((state) => ({ value: state.value + 1}));
这会给我们 this.state.value === 3
同一周期内的多个呼叫可以一起批处理。例如,如果您尝试在同一周期内多次增加项目数量,则将导致以下结果:
Object.assign(
previousState,
{quantity: state.quantity + 1},
{quantity: state.quantity + 1},
...
)
https://reactjs.org/docs/react-component.html
如文档中
的setState()入列更改组件状态并告诉阵营,这个组件和它的孩子需要重新渲染与更新的状态。这是用于响应事件处理程序和服务器响应而更新用户界面的主要方法。
它将按照队列中的顺序执行更改(FIFO:先进先出),第一个调用将首先执行
文章标签:javascript , reactjs , setstate , state
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!
评论已关闭!