setState机制

setState作为react中的重要部分,将对组件 state 的更改排入队列,并通知 React 需要使用更新后的 state 重新渲染此组件及其子组件。这是用于更新用户界面以响应事件处理器和处理服务器数据的主要方式。

setState是同步还是异步?

  • setState只在合成事件和钩子函数、生命周期函数中是“异步”的,在原生事件和setTimeout 中都是同步的
  • setState很多时候并不是立即执行,所以在setState之后立即调用state可能不会得到理想的state的值。componentDidUpdate 或者 setState 的回调函数(setState(updater, callback))这两种方式都可以保证在应用更新后触发
  • setState 通过一个队列机制实现 state 更新。当执行 setState 时,会将需要更新的 state 合并后放入状态队列,而不会立刻更新 this.state,队列机制可以高效地批量更新 state。
  • reason:因为setState的更新会导致re-rendering,如果每次setState都重新re-rendering,会导致组件的渲染问题,所以react将state的更新进行队列处理,不会导致立即更新,在state的更新进入队列后,再进行批量更新。

setState源码相关

// 将新的 state 合并到状态更新队列中
var nextState = this._processPendingState(nextProps, nextContext); 
// 根据更新队列和 shouldComponentUpdate 的状态来判断是否需要更新组件
var shouldUpdate = 
 this._pendingForceUpdate || 
 !inst.shouldComponentUpdate || 
 inst.shouldComponentUpdate(nextProps, nextState, nextContext);
如果在 shouldComponentUpdatecomponentWillUpdate 方法中调用 setState ,此时
this._pendingStateQueue != null,则 performUpdateIfNecessary 方法就会调用 updateComponent
方法进行组件更新,但 updateComponent 方法又会调用 shouldComponentUpdate 和 componentWillUpdate 方法,因此造成循环调用,使得浏览器内存占满后崩溃
import React, { Component } from 'react'; 
class Example extends Component { 
 constructor() { 
 super(); 
 this.state = { 
 val: 0 
 }; 
 } 
 componentDidMount() {
 this.setState({val: this.state.val + 1}); 
 console.log(this.state.val); // 第 1 次输出 0
 this.setState({val: this.state.val + 1}); 
 console.log(this.state.val); // 第 2 次输出 0
 setTimeout(() => { 
 this.setState({val: this.state.val + 1}); 
console.log(this.state.val); // 第 3 次输出 2
 this.setState({val: this.state.val + 1}); 
console.log(this.state.val); // 第 4 次输出 3
 }, 0); 
 } 
 render() { 
 return null; 
 } 
}

 setState注意事项:

state的更新可能是异步的,所以不要期待用当前state的值来更新state。//下面的方法可能无法更新

this.setState({
  counter: this.state.counter + this.props.increment,
});

要解决上面的问题,可以让setState接受一个函数而不是一个参数

this.setState((state, props) => ({
  counter: state.counter + props.increment
}));

此时的state参数是当前的state,props是当前props

 

把需要在 setState 更新之后进行的逻辑放在一个合适的生命周期 hook 函数中,比如 componentDidMount 或者 componentDidUpdate 也当然可以解决问题。也就是说 count 第一次 +1 之后,触发 componentDidUpdate 生命周期 hook,第二次 count +1 操作直接放在 componentDidUpdate 函数里面就好啦。setState的更新会带来生命周期的再次执行,则state的值会进行更新。

posted @ 2021-09-20 17:43  千亿昔  阅读(238)  评论(0编辑  收藏  举报