關於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,就會形成循環調用,使得瀏覽器內存佔滿後崩潰。(親測有效)

相關文章
相關標籤/搜索