彻底理解React中的this.setState

一、this.setState的作用

当我们需要更新this.state中的数据时候,不要直接修改this.state。虽然状态值可以改变,但是不会触发组件的更新。因此我们需要调用this.setState。React中constructor是唯一可以初始化state的地方。也可以把它理解成一个钩子函数,该函数最先执行且只执行一次。

二、this.setState的基本使用

this.setState(),该方法接收两种参数:对象或函数

对象:即想要修改的state

函数:接收两个函数,第一个函数接受两个参数,第一个是当前state,第二个是当前props,该函数返回一个对象,和直接传递对象参数是一样的,就是要修改的state;第二个参数是一个函数,我们可以在这个函数中验证数据是否修改成功,以及获取到数据更新后最新的dom结构

this.setState({
  message:"Alley"
})

this.setState((state,props)=>({
  message:"alley"
}),()=>{
  console.log("修改成功")
})

三、this.setState执行后都做了哪些事情?

事实上this.setState内部执行过程是很复杂的,大致过程包括更新state,创建新的VNode,再经过diff算法比对差异,决定渲染哪一部分以及怎么渲染,最终形成最新的UI。

this.setState执行后执行的生命周期函数

  • shouleComponentUpdate
  • componentWillUpdate
  • render
  • componentDidUpdate

this.setState执行后做的一些事情

  • this.setState(newState) =>
  • newState存入pending队列 =>
  • 调用enqueueUpdate =>
  • 是否处于批量更新模式 => 是的话将组件保存到dirtyComponents
  • 不是的话遍历dirtyComponents,调用updateComponent,更新pending state or props
/enqueueUpdate的源码如下:

function enqueueUpdate(component){
       //injected注入的
       ensureInjected();
       //如果不处于批量更新模式
       if(!batchingStrategy.isBatchingUpdates){
           batchingStrategy.batchedUpdates(enqueueUpdate, component);
           return;
       }
       //如果处于批量更新模式
       dirtyComponents.push(component);
   } 
  • 如果isBatchingUpdates为false,则对所有队列中的更新执行batchedUpdates方法,否则只把当前组件(即调用了setState的组件)放入dirtyComponents数组中。
  • 连续调用了多次setState,但是只引发了一次更新生命周期,因为React会将多个this.setState产生的修改放在一个队列里,缓一缓,攒在一起,觉得差不多了在引发一次更新过程。所以攒的过程中如果你不停的set同一个state的值,只会触发最后一次

四、this.setState为什么是异步的?

this.setState本身的执行过程是同步的,只是因为在react的合成事件与钩子函数中执行顺序在更新之前,所以不能直接拿到更新后的值,形成了所谓的"异步"

假如this.setState是同步更新的,每更新一次,那四个生命周期都要完整执行一次,无疑会造成性能问题。事实上这些生命周期为纯函数,对性能还好,但是diff比较、更新DOM总会消耗时间和性能。

此外为了批次和性能,多个setState有可能在执行过程中还会被合并,所以setState延时异步更新是很合理的

五、React中的this.setState什么时候是同步的什么时候是异步的?

setState只在合成事件和钩子函数中是异步的,而在原生事件和setTimeout中是同步的

  • 合成事件:react 在组件中的onClick等都是属于它自定义的合成事件
  • 原生事件:比如通过addeventListener添加的,dom中的原生事件

setState的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形式了所谓的“异步”,当然可以通过第二个参数 setState(partialState, callback) 中的callback拿到更新后的结果。

setState 的批量更新优化也是建立在“异步”(合成事件、钩子函数)之上的,在原生事件和setTimeout 中不会批量更新,在“异步”中如果对同一个值进行多次 setState , setState 的批量更新策略会对其进行覆盖,取最后一次的执行,如果是同时 setState 多个不同的值,在更新时会对其进行合并批量更新。

六、React是怎样控制异步和同步的

在 React 的 setState 函数实现中,会根据一个变量 isBatchingUpdates 判断是直接更新 this.state 还是放到队列中延时更新,而 isBatchingUpdates 默认是 false,表示 setState 会同步更新 this.state;但是,有一个函数 batchedUpdates,该函数会把 isBatchingUpdates 修改为 true,而当 React 在调用事件处理函数之前就会先调用这个 batchedUpdates将isBatchingUpdates修改为true,这样由 React 控制的事件处理过程 setState 不会同步更新 this.state。


WX20220701-180332.png

你可能感兴趣的:(彻底理解React中的this.setState)