关于React中setState的理解

咱们先来看一个问题浏览器

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异步更新

setState方法经过一个队列机制实现state更新,当执行setState的时候,会将须要更新的state合并以后放入状态队列,而不会当即更新this.state(能够和浏览器的事件队列类比)。component

setState简化调用栈:
图片描述orm

那么咱们要如何解决上面的问题呢?

一、利用setTimeout

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);

}

二、利用setState的回调函数

在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
});

}

三、利用Promise,进行封装

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,就会形成循环调用,使得浏览器内存占满后崩溃。(亲测有效)

相关文章
相关标签/搜索