react数据管理

1.React setState 调用的原理

具体的执行过程如下(源码级解析):

  • 首先调用了setState 入口函数,入口函数在这里就是充当一个分发器的角色,根据入参的不同,将其分发到不同的功能函数中去;
  • ReactComponent.prototype.setState = function (partialState, callback) {
  •   this.updater.enqueueSetState(this, partialState);
  •   if (callback) {
  •     this.updater.enqueueCallback(this, callback, 'setState');
  •   }};
  • enqueueSetState 方法将新的 state 放进组件的状态队列里,并调用 enqueueUpdate 来处理将要更新的实例对象;
  • enqueueSetState: function (publicInstance, partialState) {
  •   // 根据 this 拿到对应的组件实例  var internalInstance = getInternalInstanceReadyForUpdate(publicInstance, 'setState');
  •   // 这个 queue 对应的就是一个组件实例的 state 数组  var queue = internalInstance._pendingStateQueue || (internalInstance._pendingStateQueue = []);
  •   queue.push(partialState);
  •   //  enqueueUpdate 用来处理当前的组件实例  enqueueUpdate(internalInstance);}
  • 在 enqueueUpdate 方法中引出了一个关键的对象——batchingStrategy,该对象所具备的isBatchingUpdates 属性直接决定了当下是要走更新流程,还是应该排队等待;如果轮到执行,就调用 batchedUpdates 方法来直接发起更新流程。由此可以推测,batchingStrategy 或许正是 React 内部专门用于管控批量更新的对象。
  • function enqueueUpdate(component) {
  •   ensureInjected();
  •   // 注意这一句是问题的关键,isBatchingUpdates标识着当前是否处于批量创建/更新组件的阶段  if (!batchingStrategy.isBatchingUpdates) {
  •     // 若当前没有处于批量创建/更新组件的阶段,则立即更新组件    batchingStrategy.batchedUpdates(enqueueUpdate, component);
  •     return;
  •   }
  •   // 否则,先把组件塞入 dirtyComponents 队列里,让它“再等等”  dirtyComponents.push(component);
  •   if (component._updateBatchNumber == null) {
  •     component._updateBatchNumber = updateBatchNumber + 1;
  •   }}
  • 注意:batchingStrategy 对象可以理解为“锁管理器”。这里的“锁”,是指 React 全局唯一的 isBatchingUpdates变量,isBatchingUpdates 的初始值是 false,意味着“当前并未进行任何批量更新操作”。每当 React 调用 batchedUpdate 去执行更新动作时,会先把这个锁给“锁上”(置为 true),表明“现在正处于批量更新过程中”。当锁被“锁上”的时候,任何需要更新的组件都只能暂时进入 dirtyComponents 里排队等候下一次的批量更新,而不能随意“插队”。此处体现的“任务锁”的思想,是 React 面对大量状态仍然能够实现有序分批处理的基石。

2、React setState 调用之后发生了什么?是同步还是异步?

  • React中setState后发生了什么
  • 在代码中调用setState函数之后,React 会将传入的参数对象与组件当前的状态合并,然后触发调和过程(Reconciliation)。经过调和过程,React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个UI界面。

  • 在 React 得到元素树之后,React 会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染。在差异计算算法中,React 能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染。

  • 如果在短时间内频繁setState。React会将state的改变压入栈中,在合适的时机,批量更新state和视图,达到提高性能的效果。

  • setState 是同步还是异步的
  • 假如所有setState是同步的,意味着每执行一次setState时(有可能一个同步代码中,多次setState),都重新vnode diff + dom修改,这对性能来说是极为不好的。如果是异步,则可以把一个同步代码中的多个setState合并成一次组件更新。所以默认是异步的,但是在一些情况下是同步的。

  • setState 并不是单纯同步/异步的,它的表现会因调用场景的不同而不同。在源码中,通过 isBatchingUpdates 来判断setState 是先存进 state 队列还是直接更新,如果值为 true 则执行异步操作,为 false 则直接更新。
  • 异步: 在 React 可以控制的地方,就为 true,比如在 React 生命周期事件和合成事件中,都会走合并操作,延迟更新的策略。
  • 同步: 在 React 无法控制的地方,比如原生事件,具体就是在 addEventListener 、setTimeout、setInterval 等事件中,就只能同步更新。
  • 一般认为,做异步设计是为了性能优化、减少渲染次数:
  • setState设计为异步,可以显著的提升性能。如果每次调用 setState都进行一次更新,那么意味着render函数会被频繁调用,界面重新渲染,这样效率是很低的;最好的办法应该是获取到多个更新,之后进行批量更新;
  • 如果同步更新了state,但是还没有执行render函数,那么stateprops不能保持同步。stateprops不能保持一致性,会在开发中产生很多的问题;

3、 React中setState的第二个参数作用是什么?

  • setState 的第二个参数是一个可选的回调函数。这个回调函数将在组件重新渲染后执行。等价于在 componentDidUpdate 生命周期内执行。通常建议使用 componentDidUpdate 来代替此方式。在这个回调函数中你可以拿到更新后 state 的值:

this.setState({

    key1: newState1,

    key2: newState2,

    ...}, callback) // 第二个参数是 state 更新完成后的回调函数

4、在React中组件的this.state和setState有什么区别?

  • this.state通常是用来初始化state的,this.setState是用来修改state值的。如果初始化了state之后再使用this.state,之前的state会被覆盖掉,如果使用this.setState,只会替换掉相应的state值。所以,如果想要修改state的值,就需要使用setState,而不能直接修改state,直接修改state之后页面是不会更新的
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值