前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【React源码笔记】setState原理解析

【React源码笔记】setState原理解析

作者头像
腾讯VTeam技术团队
发布于 2021-01-29 07:40:18
发布于 2021-01-29 07:40:18
2.3K00
代码可运行
举报
文章被收录于专栏:VTeam技术团队VTeam技术团队
运行总次数:0
代码可运行

点击上方蓝字,发现更多精彩

导语

大家都知道React是以数据为核心的,当状态发生改变时组件会进行更新并渲染。除了通过React Redux、React Hook进行状态管理外,还有像我这种小白通过setState进行状态修改。对于React的初学者来说,setState这个API是再亲切不过了,同时也很好奇setState的更新机制,因此写了一篇文章来进行巩固总结setState。

React把组件看成是一个State Machines状态机,首先定义数值的状态state,通过用户交互后状态发生改变,然后更新渲染UI。也就是说更新组件的state,然后根据新的state重新渲染更新用户的界面。而在编写类组件时,通常分配state的地方是construtor函数。

刚开始热情满满学习的时候,总是从React官方文档开始死磕,看到state那一块,官方文档抛出了“ 关于 setState()你应该了解的三件事 “几个醒目的大字:

(1)不要直接修改state (2)state的更新可能是异步的 (3)state的更新会被合并

啊…那setState方法从哪里来?为什么setState是有时候是异步会不会有同步的呢?为什么多次更新state的值会被合并只会触发一次render?为什么直接修改this.state无效???

带着这么多的疑问,因为刚来需求也不多,对setState这一块比较好奇,那我就默默clone了react源码。今天从这四个有趣的问题入手,用setState跟大家深入探讨state的更新机制,一睹setState的芳容。源码地址入口(本次探讨是基于React 16.7.0版本,React 16.8后加入了Hook)。

1. setState API从哪里来

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Component.prototype.setState = function(partialState, callback) {  ...  this.updater.enqueueSetState(this, partialState, callback, 'setState');};

setState是挂载在组件原型上面的方法,因此用class方法继承React.Component时,setState就会被自定义组件所继承。通过调用this就可以访问到挂载到组件实例对象上的setState方法,setState方法从这来。

2. setState异步更新 && 同步更新

在react state源码注释中有这样一句话:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
There is no guarantee that this.state will be immediately updated, so accessing this.state after calling this method may return the old value.

大概意思就是说setState不能确保实时更新state,但也没有明确setState就是异步的,只是告诉我们什么时候会触发同步操作,什么时候是异步操作。

首先要知道一点,setState本身的执行过程是同步的,只是因为在react的合成事件与钩子函数中执行顺序在更新之前,所以不能直接拿到更新后的值,形成了所谓的“ 异步 ”。异步可以避免react改变状态时,资源开销太大,要去等待同步代码执行完毕,使当前的JS代码被阻塞,这样带来不好的用户体验。

那setState什么时候会执行异步操作或者同步操作呢?

简单来说,由react引发的事件处理都是会异步更新state,如

  • 合成事件(React自己封装的一套事件机制,如onClick、onChange等)
  • React生命周期函数

而使用react不能控制的事件则可以实现同步更新,如

  • setTimeout等异步操作
  • 原生事件,如addEventListener等
  • setState回调式的callback

由上面第一部分的代码可知setState方法传入参数是partialState, callback,partialState是需要修改的setState对象,callback是修改之后回调函数,如 setState({},()=>{})。我们在调用setState时,也就调用了 this.updater.enqueueSetState,updater是通过依赖注入的方式,在组件实例化的时候注入进来的,而之后被赋值为classComponentUpdater。而enqueueSetState如其名,是一个队列操作,将要变更的state统一插入队列,待一一处理。enqueueSetState函数如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const classComponentUpdater = {  isMounted,  // inst其实就是组件实例对象的this  enqueueSetState(inst, payload, callback) {  //  获取当前实例上的fiber    const fiber = getInstance(inst);    const currentTime = requestCurrentTime();    const expirationTime = computeExpirationForFiber(currentTime, fiber);    const update = createUpdate(expirationTime);    update.payload = payload;    if (callback !== undefined && callback !== null) {      if (__DEV__) {        warnOnInvalidCallback(callback, 'setState');      }      update.callback = callback;    }    flushPassiveEffects();    //    把更新放到队列中去    enqueueUpdate(fiber, update);    //     进入异步渲染的核心:React Scheduler    scheduleWork(fiber, expirationTime);  },  ...}

注释中讲到scheduleWork是异步渲染的核心,正是它里面调用了reqeustWork函数。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function requestWork(root: FiberRoot, expirationTime: ExpirationTime) {  //  根节点添加到调度任务中  addRootToSchedule(root, expirationTime);  if (isRendering) {    return;  }  //  isBatchingUpdates默认为flase,但是react事件触发后会对它重新赋值为true  if (isBatchingUpdates) {  //  isUnbatchingUpdates默认也为false    if (isUnbatchingUpdates) {      nextFlushedRoot = root;      nextFlushedExpirationTime = Sync;      performWorkOnRoot(root, Sync, false);    }    return;  }  if (expirationTime === Sync) {  //  若是isBatchingUpdates为false,则对setState进行diff渲染更新    performSyncWork();  } else {    scheduleCallbackWithExpirationTime(root, expirationTime);  }}

可以看到在这个函数中有isRendering(当React的组件正在渲染但还没有渲染完成的时候,isRendering是为true;在合成事件中为false)和isBatchingUpdates(默认为false)两个变量,而这两个变量在下文分析中起到非常重要的作用。

°

2.1 交互事件里面的setState

举个栗子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
this.state = {  name:'rosie',  age:'21',};handleClick(){  this.setState({    age: '18'  })  console.log(this.state.age) // 输出21}

可以看到在react交互事件里age并没有同步更新。

先贴张小小的流程图:

react有一套自己的事件合成机制,在合成事件调用时会用到interactiveUpdates函数。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function interactiveUpdates<A, B, R>(fn: (A, B) => R, a: A, b: B): R {  if (isBatchingInteractiveUpdates) {    return fn(a, b);  }  ...  const previousIsBatchingInteractiveUpdates = isBatchingInteractiveUpdates;   //  将previousIsBatchingUpdates赋值为false  const previousIsBatchingUpdates = isBatchingUpdates;  isBatchingInteractiveUpdates = true;  isBatchingUpdates = true;  //  关键代码块  try {    return fn(a, b);  } finally {    isBatchingInteractiveUpdates = previousIsBatchingInteractiveUpdates;    //  isBatchingUpdates变为false    isBatchingUpdates = previousIsBatchingUpdates;    if (!isBatchingUpdates && !isRendering) {      performSyncWork();    }  }}

可以看到这个函数中执行了 isBatchingUpdates=true,在执行try代码块中的fn函数(指的是从dispatchEvent 到 requestWork整个调用栈)时,在reqeustWork方法中isBatchingUpdates被修改成了true,而isUnbatchingUpdates默认为false,所以在这里直接被return了。这就表示requestWork中performSyncWork函数没有被执行到,当然其他更新函数像performWorkOnRoot也没有被执行,因此还没被更新。但是在开始的enqueueSetState函数通过 enqueueUpdate(fiber,update)语句已经把该次更新存入到了队列当中。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if (isBatchingUpdates) {  //  isUnbatchingUpdates也为false  if (isUnbatchingUpdates) {    nextFlushedRoot = root;    nextFlushedExpirationTime = Sync;    performWorkOnRoot(root, Sync, false);  }  return;}

那么在reqeustWork中被return了,会return到哪里呢?从流程图看到很显然是回到了interactiveUpdates这个方法中。因此执行setState后直接console.log是属于try代码块中的执行,由于合成事件try代码块中执行完state后并没有更新(因为没有执行到performSyncWork),因此输出还是之前的值,造成了所谓的“异步”。

等到合成事件执行完后,就进入到了finally,此时isBatchingUpdates变为false,isRendering也为false,二者取反为true则进入到了performSyncWork函数,这个函数会去更新state并且渲染对应的UI。

°

2.2 生命周期里的setState

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
this.state = {  name:'rosie',  age:'21',};componentDidMount() {  this.setState({    age: '18'   })  console.log(this.state.age) // 21}shouldComponentUpdate(){  console.log("shouldComponentUpdate",this.state.age); // 21  return true;}render(){  console.log("render",this.state.age); // 18  return{    <div></div>  }}getSnapshotBeforeUpdate(){  console.log("getSnapshotBeforeUpdate",this.state.age); // 18  return true;}componentDidUpdate(){  console.log("componentDidUpdate",this.state.age);// 18}

可以看到在componentDidMount输出结果仍然是以前的值。再贴个大大的流程图:

我们一般在componentDidMount中调用setState,当componentDidMount执行的时候,此时组件还没进入更新渲染阶段,isRendering为true,在reqeustWork函数中直接被return掉(输出旧值最重要原因),没有执行到下面的更新函数。等执行完componentDidMount后才去 commitUpdateQueue更新,导致在componentDidMount输出this.state的值还是旧值。

采用程墨大大的图,React V16.3后的生命周期如下:

那么它会经过组件更新的生命周期,会触发Component的以下4个生命周期方法,并依次执行:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
shouldComponentUpdate // 旧值render // 更新后的值getSnapshotBeforeUpdate // 更新后的值componentDidUpdate // 更新后的值

componentDidMount生命周期函数是在组件一挂载完之后就会执行,由新的生命周期图可以看到,当shouldComponentUpdate返回true时才会继续走下面的生命周期;如果返回了false,生命周期被中断,虽然不调用之后的函数了,但是state仍然会被更新。

正是在componentDidMount时直接return掉,经过了多个生命周期this.state才得到更新,也就造成了所谓的“异步”。

当然我们也不建议在componentDidMount中直接setState,在 componentDidMount 中执行 setState 会导致组件在初始化的时候就触发了更新,渲染了两遍,可以尽量避免。同时也禁止在shouldComponentUpdate中调用setState,因为调用setState会再次触发这个函数,然后这个函数又触发了 setState,然后再次触发这两个函数……这样会进入死循环,导致浏览器内存耗光然后崩溃。

°

2.3 setTimeOut中的setState

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
this.state = {  name:'rosie',  age:'21',};componentDidMount() {  setTimeout(e => {    this.setState({      age: '18'     })    console.log(this.state.age) // 18  }, 0) }

我们都知道JS有event loop事件循环机制。当script代码被执行时,遇到操作、函数调用就会压入栈。主线程若遇到ajax、setTimeOut异步操作时,会交给浏览器的webAPI去执行,然后继续执行栈中代码直到为空。浏览器webAPI会在某个时间内比如1s后,将完成的任务返回,并排到队列中去,当栈中为空时,会去执行队列中的任务。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function requestWork(root: FiberRoot, expirationTime: ExpirationTime) {  ...  if (isBatchingUpdates) {  ...    return;  }  if (expirationTime === Sync) {    performSyncWork();  } else {    scheduleCallbackWithExpirationTime(root, expirationTime);  }}

当你try代码块执行到setTimeout的时候,此时是把该异步操作丢到队列里,并没有立刻去执行,而是执行interactiveUpdates函数里的finally代码块,而previousIsBatchingUpdates在之前被赋值为false,之后又赋给了isBatchingUpdates,导致isBatchingUpdates变成false。导致最后在栈中执行setState时,也就是执行try代码块中的fn(a,b)时,进入reqeustWork函数中执行了performSyncWork,也就是可以同步更新state。

°

2.4 原生事件中的setState

原生事件指的是非react合成事件,像 addEventListener()或者 document.querySelector().onclick()等这种绑定事件的形式。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
this.state = {  name:'rosie',  age:'21',};handleClick = () => {  this.setState({    age: '18'  })  console.log(this.state.age) // 18}componentDidMount() {  document.body.addEventListener('click', this.handleClick)}

因为原生事件没有走合成过程,因此在reqeustWork中isRendering为false,isBatchingUpdates为false,直接调用了performSyncWork去更新,所以能同步拿到更新后的state值。

3. setState中的批量更新

如果每次更新state都走一次四个生命周期函数,并且进行render,而render返回的结果会拿去做虚拟DOM的比较和更新,那性能可能会耗费比较大。像以下这种:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
this.state = {  count:0,};add = () => {  for ( let i = 0; i < 10000; i++ ) {    this.setState( { count: this.state.count + 1 } );  }}

如果每次都立马执行的,在短短的时间里,会有10000次的渲染,这显然对于React来说是较大的一个渲染性能问题。那如果我不是10000次,只有两次呢?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
add = ()=>{  this.setState({    count: this.state.count + 1   });  this.setState({    count: this.state.count + 1   });}

没有意外,以上代码还是只执行了一个render,就算不是10000次计算,是2次计算,react为了提升性能只会对最后一次的 setState 进行更新。

React针对 setState 做了一些特别的优化:React 会将多个setState的调用合并成一个来执行,将其更新任务放到一个任务队列中去,当同步任务栈中的所有函数都被执行完毕之后,就对state进行批量更新。

当然你也可以用回调函数拿到每次执行后的值,此时更新不是批量的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
add = () => {  this.setState((preCount)=>({    count: preCount.count + 1   }));  this.setState((preCount)=>({    count: preCount.count + 1   }));}// 输出2

你也可以使用setTimeout更新多次:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
add = () => {  setTimeout( _=>{    this.setState({      count: this.state.count + 1     });  },0)  setTimeout( _=>{    this.setState({      count: this.state.count + 1     });  },0)}// 输出2

你上面说了setState会进行批量更新,那为啥使用回调函数或者setTimeout等异步操作能拿到2,也就是render了两次呢??

首先只render一次即批量更新的情况,由合成事件触发时,在reqeustWork函数中isBatchingUpdates将会变成true,isUnbatchingUpdates为false则直接被return掉了。但是之前提到它会在开始的enqueueSetState函数通过enqueueUpdate(fiber, update)已经把该次更新存入到了队列当中,在enqueueUpdate函数中传入了fiber跟update两个参数。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  enqueueSetState(inst, payload, callback) {    //    获取当前实例上的fiber    const fiber = getInstance(inst);    //    计算当前时间    const currentTime = requestCurrentTime();    //    计算当前fiber的到期时间,为计算优先级作准备    const expirationTime = computeExpirationForFiber(currentTime, fiber);    //    创建更新一个update    const update = createUpdate(expirationTime);    //    payload是要更新的对象    update.payload = payload;    //    callback回调函数    if (callback !== undefined && callback !== null) {      if (__DEV__) {        warnOnInvalidCallback(callback, 'setState');      }      update.callback = callback;    }    flushPassiveEffects();    //    重点:把更新放到队列中去    enqueueUpdate(fiber, update);    //     进入异步渲染的核心:React Scheduler    scheduleWork(fiber, expirationTime);  },

简单提一下,为了避免更新的过程中长时间阻塞主线程,在React 16之后加入了Fiber架构,它能将整个更新任务拆分为一个个小的任务,并且能控制这些任务的执行。而fiber是一个工作单元,是把控这个拆分的颗粒度的数据结构。

加入Fiber架构后,react在任务调度之前通过enqueueUpdate函数调度,里面修改了Fiber的updateQueue对象的任务,即维护了fiber.updateQueue,最后调度会调用一个getStateFromUpdate方法来获取最终的state状态,而这个方法里面的这段代码显得尤为关键:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function getStateFromUpdate<State>(  workInProgress: Fiber,  queue: UpdateQueue<State>,  update: Update<State>,  prevState: State,  nextProps: any,  instance: any,): any {  switch (update.tag) {    ...    case UpdateState: {      const payload = update.payload;      let partialState;      //  当payload为函数类型时      if (typeof payload === 'function') {          ...           partialState = payload.call(instance, prevState, nextProps);           ...      }      ...      // 重点:通过Object.assign生成一个全新的state,和未更新的部分state进行合并      return Object.assign({}, prevState, partialState);    }   ...  }  return prevState;}

看到Object.assign是不是很熟悉?preState是原先的状态,partialState是将要更新后的状态,Object.assign就是对象合并。那么 Object.assign({},{count:0},{count:1})最后返回的是{count:1}达到了state的更新。

我们刚才花了一大篇幅来证明在react合成事件和生命周期下state的更新是异步的,主要体现在interactiveUpdates函数的try finally模块,在try模块执行时不会立刻更新,因此导致三次setState的prevState值都是0,两次setState的partialState都是1。执行两次 Object.assign({},{count:0},{count:1})最后结果不还是返回1吗?

因此也可以得出state的批量更新是建立在异步之上的,那setTimeout同步更新state就导致state没有批量更新,最后返回2。

那callBack回调函数咋就能也返回2呢?我们知道payload的类型是function时,通过 partialState=payload.call(instance,prevState,nextProps)语句的执行,能获取执行回调函数后得到的state,将其赋值给每次partialState。每次回调函数都能拿到更新后的state值,那就是每次partialState都进行了更新。在进行Object.assign对象合并时,两次prevState的值都是0,而partialState第一次为1,第二次为2,像如下这样:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Object.assign({}, {count:0}, {count:1});Object.assign({}, {count:0}, {count:2});

也就最后返回了2。所以如果你不想拿到setState批量更新后的值,直接用回调函数就好啦。

4. 直接修改this.state无效

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
this.state.comment = 'Hello world';

直接以赋值形式修改state,不会触发组件的render。

通过上面的分析,可以得出setState本质是通过一个更新队列机制实现更新的,如果不通过setState而直接修改this.state,那么这个state不会放入状态更新队列中,也就不会render,因此修改state的值必须通过setState来进行。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
this.setState({  comment: 'Hello world'})

5. 小Tips && 小总结

更新对象:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
this.setState(preState=> ({  obj: Object.assign({}, preState.obj, {name: 'Tom'})}))this.setState(preState=> ({  obj: {...preState.obj,name:'Tom'}}))

更新数组:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
this.setState((perState)=>{  return {arr:perState.arr.concat(1)}})this.setState((perState)=>{  return {arr:[...perState.arr,1]}})this.setState((perState)=>{  return {arr:perState.arr.slice(1,4)}})

注意,不要使用push、pop、shift、unshift、splice等方法修改数组类型的状态,因为这些方法都是在原数组的基础上修改的,返回值不是新的数组,而是返回长度或者修改的数组部分等。而concat、slice、filter会生成一个新的数组。

总结:通过探讨React state的更新机制,更加理解了React深层更新的运作流程。感觉React还是非常的博大精深,希望以后继续探讨下去哈哈哈,欢迎大家批评指正!

END

更多精彩推荐,请关注我们

你的每个赞和在看,我都喜欢!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-01-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 腾讯VTeam技术团队 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
深入理解 React setState
React 修改 state 方法有两种: 1、构造函数里修改 state ,只需要直接操作 this.state 即可, 如果在构造函数里执行了异步操作,就需要调用 setState 来触发重新渲染。 2、在其余的地方需要改变 state 的时候只能使用 setState,这样 React 才会触发 UI 更新,如果在其余地方直接修改 state 中的值,会报错:
Leophen
2021/07/08
1.1K0
React中的setState的同步异步与合并(2)
this.setState会通过引发一次组件的更新过程来引发重新绘制。也就是说setState的调用会引起React的更新生命周期的四个函数的依次调用:
Qwe7
2022/06/09
7020
React源码学习进阶(八)setState底层逻辑
setState的实现还是一如既往的简单,位于packages/react/src/ReactBaseClasses.js:
孟健
2022/12/19
9120
React源码学习进阶(八)setState底层逻辑
小前端读源码 - React16.7.0(深入了解setState)
但是对于阅读React源码的角度来说还不够,在上面文章最后有提到的一些阅读计划,本篇文章将去阅读在我们触发setState的时候到底代码是如何执行的,中间会经过哪些流程。
LamHo
2022/09/26
7570
小前端读源码 - React16.7.0(深入了解setState)
React进阶篇(四)事务
根据维基百科的解释: 提供独立可靠的恢复机制,保证出错时数据的一致性,不同事务之间互相独立。
娜姐
2020/12/11
1.2K0
React进阶篇(四)事务
你真的理解setState吗?
作者:虹晨,来源:https://juejin.im/post/5b45c57c51882519790c7441
zz_jesse
2020/06/05
1.5K0
你真的理解setState吗?
[第10期] 了解 React setState 运行机制
使用React 的时候, 难免要用到setState , 有一些基础还是需要了解一下。
皮小蛋
2020/03/02
1.2K0
揭密React setState
学过react的人都知道,setState在react里是一个很重要的方法,使用它可以更新我们数据的状态,本篇文章从简单使用到深入到setState的内部,全方位为你揭开setState的神秘面纱~
IMWeb前端团队
2019/12/03
1K1
揭密React setState
React源码解析之setState和forceUpdate
一、enqueueSetState() 非异步方法中,无论调用多少个setState,它们都会在最后一次setState后,放入更新队列,然后执行一次统一的更新,详情请参考: React.setState之state批处理的机制 和 为什么React.setState是异步的?
进击的小进进
2019/09/05
1.4K0
React源码解析之setState和forceUpdate
react面试如何回答才能让面试官满意
注意:batchingStrategy 对象可以理解为“锁管理器”。这里的“锁”,是指 React 全局唯一的 isBatchingUpdates 变量,isBatchingUpdates 的初始值是 false,意味着“当前并未进行任何批量更新操作”。每当 React 调用 batchedUpdate 去执行更新动作时,会先把这个锁给“锁上”(置为 true),表明“现在正处于批量更新过程中”。当锁被“锁上”的时候,任何需要更新的组件都只能暂时进入 dirtyComponents 里排队等候下一次的批量更新,而不能随意“插队”。此处体现的“任务锁”的思想,是 React 面对大量状态仍然能够实现有序分批处理的基石。
beifeng1996
2022/09/22
9620
React和Vue中,是如何监听变量变化的
假设有这样一个场景,父组件传递子组件一个A参数,子组件需要监听A参数的变化转换为state。
用户2356368
2019/04/03
4.8K0
React和Vue中,是如何监听变量变化的
React源码解析之updateClassComponent(上)
前言: 本篇文章给大家带来的是updateClassComponent ()的讲解,即 ClassComponet 的更新流程:
进击的小进进
2020/02/13
8150
React源码解析之updateClassComponent(上)
React State(状态): React通过this.state来访问state,通过this.setState()方法来更新stateReact State(状态)
React 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。 React 里,只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。 以下实例中创建了 LikeButton 组件,getInitialState 方法用于定义初始状态,也就是一个对象,这个对象可以通过 this.state 属性读取。当用户点击组件,导致状态变化,this.setState 方法就修改状态值,每次修改以后,自动调用 this.render 方法,再次渲染组件。
一个会写诗的程序员
2018/08/17
2K0
React源码学习入门(十)setState是怎么做到异步化的?
让我们来回顾一下(源码位于src/isomorphic/modern/class/ReactBaseClasses.js):
孟健
2022/12/19
5870
React源码学习入门(十)setState是怎么做到异步化的?
小前端读源码 - React组件更新原理
年后一直忙于工作,导致一直没有去继续阅读React的更新原理。今天我们接着往下阅读吧!
LamHo
2022/09/26
6360
小前端读源码 - React组件更新原理
React中的setState的同步异步与合并
原理可以用这张图来描述,即在react中,setState通过一个队列机制实现state的更新。当执行setState时,会把需要更新的state合并后放入状态队列,而不会立刻更新this.state,当进入组件可更新状态时,这个队列机制就会高效的批量的更新state。
Qwe7
2022/06/09
1.6K0
React中的setState是异步的吗?
在React中更新状态,一般的写法都是this.setState({a:1}),而非Vue那样this.a = 1。并且,如果在如下场景:
娜姐
2020/09/22
2.3K0
React中的setState是异步的吗?
从recat源码角度看setState流程
setState() 将对组件 state 的更改排入队列批量推迟更新,并通知 React 需要使用更新后的 state 重新渲染此组件及其子组件。其实setState实际上不是异步,只是代码执行顺序不同,有了异步的感觉。
flyzz177
2022/09/27
5220
setState 到底是同步的,还是异步的
这是一道变体繁多的面试题,在 BAT 等一线大厂的面试中考察频率非常高。首先题目会给出一个这样的 App 组件,在它的内部会有如下代码所示的几个不同的 setState 操作:
coder_koala
2021/07/08
7880
setState 到底是同步的,还是异步的
React setState 是异步执行还是同步执行?
把 setState 放在定时器里就会同步更新。放在自定义事件函数里也会同步更新,例如:
多云转晴
2020/08/04
2.6K0
React setState 是异步执行还是同步执行?
相关推荐
深入理解 React setState
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档