咱们先来看一个问题浏览器
class Test extends React.Component {
constructor(props) {异步
super(props); this.state = { num: 0, };
}
componentWillMount() {async
this.setState({ num: this.state.num + 1, }); console.log(this.state.num); this.setState({ num: this.state.num + 1, }); console.log(this.state.num);
}
render() {函数
console.log(this.state.num); return (<div />);
}
}性能
export default Test;
在上面这段代码中3个console.log()分别打印出来的num是多少呢?this
不少人会认为是:1 2 2,可是打印出来的是0 0 1。spa
因此咱们能够很肯定认为setState这个在React中用来更新state的方法是一个异步的方法。code
setState方法经过一个队列机制实现state更新,当执行setState的时候,会将须要更新的state合并以后放入状态队列,而不会当即更新this.state(能够和浏览器的事件队列类比)。component
setState简化调用栈:orm
那么咱们要如何解决上面的问题呢?
componentWillMount() {
setTimeout(() => { this.setState({ num: this.state.num + 1, }); console.log(this.state.num); // 1 this.setState({ num: this.state.num + 1, }); console.log(this.state.num); // 2 }, 0);
}
在React的官方文档中:
setState(updater[, callback])
updater的函数以下
(prevState, props) => stateChange
因此咱们能够经过回调去实时获取它更新的值:
componentWillMount() {
this.setState(((num) => { num.num++; }), () => { console.log(this.state.num); // 2 }); this.setState(((num) => { num.num++; }), () => { console.log(this.state.num); // 2 });
}
setStatePromise(updator) {
return new Promise(((resolve, reject) => { this.setState(updator, resolve); }));
}
componentWillMount() {
this.setStatePromise(({ num }) => ({ num: num + 1, })).then(() => { console.log(this.state.num); });
}
一、在State更新时,若是更新的值涉及到了state和props,我须要注意在调用setState时不要直接使用this.props和this.state,在React文档中这样说到:
React may batch multiple setState() calls into a single update for performance.
// React可能会将多个setState()调用批量处理为单个更新以提升性能。
Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state.
// 由于this.props和this.state可能会异步更新,因此不该该依赖它们的值来计算下一个状态。
那么咱们怎样去解决这个问题呢?
this.setState((prevState, props) => ({ counter: prevState.counter + props.increment}));二、若是在shouldComponentUpdate或者componentWillUpdate方法中调用setState,此时this._pending-StateQueue != null,就会形成循环调用,使得浏览器内存占满后崩溃。(亲测有效)