React源码解析笔记---调度更新(一)

本文探讨了React调度更新的机制,包括ReactDom.render、setState和forceUpdate的更新方式。详细解析了updateContainer函数,重点讲解了requestCurrentTime、msToExpirationTime和computeExpirationForFiber等关键函数的作用,阐述了React如何计算和合并更新任务以提高效率。
摘要由CSDN通过智能技术生成

前言:为了搞清楚react到底是个什么样的“框架”以及它的内部机制,因此开始阅读react源码。在阅读源码的时候,为了梳理流程,根据自己的理解以及网上的一些资料做了一些(大致流程的)笔记。笔记是当时的理解,写的时候,仍然有很多不理解的地方待后续完善。而写出来的部分,可能会有很多理解不到位甚至是错误的地方,一旦有新的理解或者发现了错误,会补充与修正。

react源码版本:16.8.6

调度更新

react调度更新主要有几种方式:ReactDom.render、setState、forceUpdate;
ReactDom.render则是通过调用updateContainer去执行更新;后两者则分别通过调用enqueueSetState、enqueueForceUpdate去更新。这三个函数很相似,所以只要看其中一个就可以了。

看一下updateContainer函数源码:

export function updateContainer(
  element: ReactNodeList,
  container: OpaqueRoot, // container, 通过render传过来的FiberRoot实例对象
  parentComponent: ?React$Component<any, any>,
  callback: ?Function,
): ExpirationTime {
   
  const current = container.current; // Fiber实例对象
  const currentTime = requestCurrentTime(); // 获取currentTime
  const expirationTime = computeExpirationForFiber(currentTime, current);
  return updateContainerAtExpirationTime(
    element,
    container,
    parentComponent,
    expirationTime,
    callback,
  );
}

可以看到它做了这几件事:
① 获取了Fiber对象;
② 计算了currentTime;
③ 计算expirationTime;
④ 调用updateContainerAtExpirationTime并取它的返回值返回;

获取currentTime调用了requestCurrentTime这个函数,看一下这个函数的代码:
代码路径:packages/react-reconciler/src/ReactFiberScheduler.js

// Expiration times are computed by adding to the current time (the start
// time). However, if two updates are scheduled within the same event, we
// should treat their start times as simultaneous, even if the actual clock
// time has advanced between the first and second call.

// In other words, because expiration times determine how updates are batched,
// we want all updates of like priority that occur within the same event to
// receive the same expiration time. Otherwise we get tearing.
let currentEventTime: ExpirationTime = NoWork;

export function requestCurrentTime() {
   
  if (workPhase === RenderPhase || workPhase === CommitPhase) {
   
    // We're inside React, so it's fine to read the actual time.
    return msToExpirationTime(now());
  }
  // We're not inside React, so we may be in the middle of a browser event.
  if (currentEventTime !== NoWork) {
   
    // Use the same start time for all updates until we enter React again.
    return currentEventTime;
  }
  // This is the first update since React yielded. Compute a new start time.
  currentEventTime = msToExpirationTime(now());
  return currentEventTime;
}

这里面有三种情况:

  • 如果是处于RenderPhase和CommitPhase阶段,重新获取时间;
  • 如果是不是处于RenderPhase ,CommitPhase阶段,而且currentEventTime不处于NoWork就说明react正在处理浏览器事件,React想让来自同一事件的相同优先级的更新的保持相同的时间,因此直接返回之前的时间;
  • 如果currentEventTime处于NoWork阶段,就说明是初次更新。计算,更新并返回时间;

然后看一下是怎么计算开始时间的,这里用了一个转化函数msToExpirationTime,将毫秒转化为expirationTime,函数参数是now(),看一下这个now是什么,跳转到:packages/react-reconciler/src/SchedulerWithReactIntegration.js

let initialTimeMs: number = Scheduler_now();

// If the initial timestamp is reasonably small, use Scheduler's `now` directly.
// This will be the case for modern browsers that support `performance.now`. In
// older browsers, Scheduler falls back to `Date.now`, which returns a Unix
// timestamp. In that case, subtract the module initialization time to simulate
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值