react源码分析(13)-updateQueue介绍(2)以及Lane模型

目录

2021SC@SDUSC

介绍getStateFromUpdate

谈谈update任务在react中的调用处理

Lane模型简介

谈谈react源码中的位运算

总结


2021SC@SDUSC

介绍getStateFromUpdate

在getStateFromUpdate函数中,通过更新任务将State进行更新。

function getStateFromUpdate<State>(
  workInProgress: Fiber,
  queue: UpdateQueue<State>,
  update: Update<State>,
  prevState: State,
  nextProps: any,
  instance: any,
): any {
  switch (update.tag) {
    case ReplaceState: {
      const payload = update.payload;
      if (typeof payload === 'function') {
        // Updater function
       
        const nextState = payload.call(instance, prevState, nextProps);
      
        return nextState;
      }
      // State object
      return payload;
    }
    case CaptureUpdate: {
      workInProgress.flags =
        (workInProgress.flags & ~ShouldCapture) | DidCapture;
    }
    // Intentional fallthrough
    case UpdateState: {
      const payload = update.payload;
      let partialState;
      if (typeof payload === 'function') {
        // Updater function
        
        partialState = payload.call(instance, prevState, nextProps);
        
      } else {
        // Partial state object
        partialState = payload;
      }
      if (partialState === null || partialState === undefined) {
        // Null and undefined are treated as no-ops.
        return prevState;
      }
      // Merge the partial state and the previous state.
      return Object.assign({}, prevState, partialState);
    }
    case ForceUpdate: {
      hasForceUpdate = true;
      return prevState;
    }
  }
  return prevState;
}

首先辨认更新过程中的标志(也就是update.tag),假如是ReplaceState,也就是对State进行替换,调用update中的payload进行计算实例中的新State(如果payload为函数),假如payload并非函数那就直接将payload返回。当标志为UpdateState时,计算新State的方法与上面类似,但这里会将计算出的新属性与以前的State合并作为newState返回。假如是ForceUpdate,则将hasForceUpdate标记为true,以后再进行处理。假如是CaptureUpdate,那么就更改节点中的Flag,这里涉及到Flow的位运算技巧,假如应当捕获的话,就会将其中的ShouldCapture属性移除并添加DidCapture属性。

谈谈update任务在react中的调用处理

首先,update的创建以及放入updateQueue的位置主要是在updateContainer处,以下为源码:

export function updateContainer(
  element: ReactNodeList,
  container: OpaqueRoot,
  parentComponent: ?React$Component<any, any>,
  callback: ?Function,
): Lane {
  if (__DEV__) {
    onScheduleRoot(container, element);
  }
  const current = container.current;
  const eventTime = requestEventTime();
  const lane = requestUpdateLane(current);

  if (enableSchedulingProfiler) {
    markRenderScheduled(lane);
  }

  const context = getContextForSubtree(parentComponent);
  if (container.context === null) {
    container.context = context;
  } else {
    container.pendingContext = context;
  }

  if (__DEV__) {
    if (
      ReactCurrentFiberIsRendering &&
      ReactCurrentFiberCurrent !== null &&
      !didWarnAboutNestedUpdates
    ) {
      didWarnAboutNestedUpdates = true;
      console.error(
        'Render methods should be a pure function of props and state; ' +
          'triggering nested component updates from render is not allowed. ' +
          'If necessary, trigger nested updates in componentDidUpdate.\n\n' +
          'Check the render method of %s.',
        getComponentNameFromFiber(ReactCurrentFiberCurrent) || 'Unknown',
      );
    }
  }

  const update = createUpdate(eventTime, lane);
  // Caution: React DevTools currently depends on this property
  // being called "element".
  update.payload = {element};

  callback = callback === undefined ? null : callback;
  if (callback !== null) {
    if (__DEV__) {
      if (typeof callback !== 'function') {
        console.error(
          'render(...): Expected the last optional `callback` argument to be a ' +
            'function. Instead received: %s.',
          callback,
        );
      }
    }
    update.callback = callback;
  }

  enqueueUpdate(current, update, lane);
  const root = scheduleUpdateOnFiber(current, lane, eventTime);
  if (root !== null) {
    entangleTransitions(root, current, lane);
  }

  return lane;
}

export {
  batchedUpdates,
  deferredUpdates,
  discreteUpdates,
  flushControlled,
  flushSync,
  flushSyncWithoutWarningIfAlreadyRendering,
  flushPassiveEffects,
};

在update中,update中的eventTime根据requestEventTime获取,而lane则根据container中的current节点进行判断,然后根据eventTime与lane创建update,并将其标签设置为updateState,含义为更新状态,这在上一篇博客中已经阐述。将update的载荷设置为当前节点的element,然后将callback设置为update的callback,然后通过enqueueUpdate将update放入updateQueue中。至于对update的处理procressUpdateQueue,在多处都有所调用,主要集中在workLoop中beginWork函数的更新节点部分(比如updateClassComponent,updateHostRoot等),在beginWork中对节点的updateQueue进行调用,从而得到新的状态。

Lane模型简介

Lane同样为优先级机制,但与Scheduler不同,属于另一套优先级机制,有不同的lane种类代表不同的优先级,这里给出lane的种种类型。

// Lane values below should be kept in sync with getLabelForLane(), used by react-devtools-scheduling-profiler.
// If those values are changed that package should be rebuilt and redeployed.

export const TotalLanes = 31;

export const NoLanes: Lanes = /*                        */ 0b0000000000000000000000000000000;
export const NoLane: Lane = /*                          */ 0b0000000000000000000000000000000;

export const SyncLane: Lane = /*                        */ 0b0000000000000000000000000000001;

export const InputContinuousHydrationLane: Lane = /*    */ 0b0000000000000000000000000000010;
export const InputContinuousLane: Lanes = /*            */ 0b0000000000000000000000000000100;

export const DefaultHydrationLane: Lane = /*            */ 0b0000000000000000000000000001000;
export const DefaultLane: Lanes = /*                    */ 0b0000000000000000000000000010000;

这里用1的个数来代表lane中的优先级,这其中,可将lane比喻为车道,1表明可在其中的车道中行驶,又根据范围划分为不同的车道区间,这里通过一些lane的计算方法体现lane的作用,首先是在处理更新队列过程中的函数isSubsetOfLanes,以下为源码

export function isSubsetOfLanes(set: Lanes, subset: Lanes | Lane) {
  return (set & subset) === subset;
}

前面为lane区间,后者为lane区间或者lane,将第一个参数的lane区间与第二个参数进行与运算,由二进制的位运算很容易得知假如第二个参数为第一个参数的子区间或者元素,那么两者的与结果就是子区间或者元素本身。这也可以解释为何Nolane总是在任意lane区间中。

接下来是processUpdateQueue中的mergeLanes函数:

export function mergeLanes(a: Lanes | Lane, b: Lanes | Lane): Lanes {
  return a | b;
}

通过或运算将两个Lane区间进行合并从而为节点增添另一个区间。

这就是对update中lane优先级的简单介绍。

谈谈react源码中的位运算

首先的用途,就像在上文中所描述的那样,方便Lane模型的运算。另外,还有一些在属性标记过程中常用的符号,比如:

workInProgress.flags |= PerformedWork;

含义为在workInProgress的flags中添加performedWork。

再比如上文中所提到的

 workInProgress.flags =
        (workInProgress.flags & ~ShouldCapture) | DidCapture;

含义为首先在workInProgress的flags中移除ShouldCapture并且添加DidCapture属性。

总结

在这里介绍了处理updateQueue中的getStateFromUpdate函数,updateQueue在react源码中的具体调用的位置和相关处理,Lane模型的具体原理以及react源码中的与位运算相关的应用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值