Skip to content

05.加入优先级的初始化渲染

react-reconciler/src/ReactFiberRoot.js

diff
+import { NoLanes } from './ReactFiberLane';

function FiberRootNode(containerInfo) {
  this.containerInfo = containerInfo;
+ this.pendingLanes = NoLanes;
}

react-reconciler/src/ReactFiber.js

js
import { NoLanes } from './ReactFiberLane';
export function FiberNode(tag, pendingProps, key) {
  ...
  this.lanes = NoLanes;
}

react-reconciler/src/ReactFiberReconciler.js

js
import { createFiberRoot } from "./ReactFiberRoot";
import { createUpdate, enqueueUpdate } from "./ReactFiberClassUpdateQueue";
import { scheduleUpdateOnFiber, requestUpdateLane } from "./ReactFiberWorkLoop";
export function createContainer(containerInfo) {
  return createFiberRoot(containerInfo);
}
export function updateContainer(element, container) {
  const current = container.current;
  const lane = requestUpdateLane(current);
  const update = createUpdate(lane);
  update.payload = { element };
  const root = enqueueUpdate(current, update, lane);
  scheduleUpdateOnFiber(root, current, lane);
}

react-reconciler/src/ReactFiberWorkLoop.js

js
export function requestUpdateLane() {
  const updateLane = getCurrentUpdatePriority();
  if (updateLane !== NoLanes) {
    return updateLane;
  }
  const eventLane = getCurrentEventPriority();
  return eventLane;
}
js
import {
  scheduleCallback as Scheduler_scheduleCallback,
  shouldYield,
  ImmediatePriority as ImmediateSchedulerPriority,
  UserBlockingPriority as UserBlockingSchedulerPriority,
  NormalPriority as NormalSchedulerPriority,
  IdlePriority as IdleSchedulerPriority,
} from "./scheduler";

import {
  NoLanes, markRootUpdated, getNextLanes,
  getHighestPriorityLane, SyncLane
} from './ReactFiberLane';
import {
  getCurrentUpdatePriority,
  lanesToEventPriority,
  DiscreteEventPriority,
  ContinuousEventPriority,
  DefaultEventPriority,
  IdleEventPriority
} from './ReactEventPriorities'
import { getCurrentEventPriority } from 'react-dom-bindings/src/client/ReactDOMHostConfig'

let workInProgressRoot = null;
let workInProgressRenderLanes = NoLanes;
diff
-export function scheduleUpdateOnFiber(root, fiber, lane) {
+export function scheduleUpdateOnFiber(root, fiber, lane) {
+ markRootUpdated(root, lane);
  ensureRootIsScheduled(root);
}
js
function ensureRootIsScheduled(root) {
  const nextLanes = getNextLanes(root, NoLanes);
  let newCallbackPriority = getHighestPriorityLane(nextLanes);
  if (newCallbackPriority === SyncLane) {

  } else {
    let schedulerPriorityLevel;
    switch (lanesToEventPriority(nextLanes)) {
      case DiscreteEventPriority:
        schedulerPriorityLevel = ImmediateSchedulerPriority;
        break;
      case ContinuousEventPriority:
        schedulerPriorityLevel = UserBlockingSchedulerPriority;
        break;
      case DefaultEventPriority:
        schedulerPriorityLevel = NormalSchedulerPriority;
        break;
      case IdleEventPriority:
        schedulerPriorityLevel = IdleSchedulerPriority;
        break;
      default:
        schedulerPriorityLevel = NormalSchedulerPriority;
        break;
    }
    Scheduler_scheduleCallback(schedulerPriorityLevel, performConcurrentWorkOnRoot.bind(null, root));
  }
}
diff
function performConcurrentWorkOnRoot(root, timeout) {
+  const nextLanes = getNextLanes(root, NoLanes);
+  if (nextLanes === NoLanes) {
+    return null;
+  }
+  renderRootSync(root, nextLanes);
  const finishedWork = root.current.alternate;
  root.finishedWork = finishedWork;
  commitRoot(root);
  return null;
}
+function prepareFreshStack(root, renderLanes) {
+  if (root !== workInProgressRoot || workInProgressRenderLanes !== renderLanes) {
    workInProgress = createWorkInProgress(root.current, null);
+  }
+  workInProgressRenderLanes = renderLanes;
  finishQueueingConcurrentUpdates();
}
+function renderRootSync(root, renderLanes) {
+  prepareFreshStack(root, renderLanes);
  workLoopSync();
}
diff
function performUnitOfWork(unitOfWork) {
  const current = unitOfWork.alternate;
+ const next = beginWork(current, unitOfWork, workInProgressRenderLanes);
  unitOfWork.memoizedProps = unitOfWork.pendingProps;
  if (next === null) {
    completeUnitOfWork(unitOfWork);
  } else {
    workInProgress = next;
  }
}
diff
function commitRoot(root) {
  const { finishedWork } = root;
+  workInProgressRoot = null;
+  workInProgressRenderLanes = null;
  if ((finishedWork.subtreeFlags & Passive) !== NoFlags
    || (finishedWork.flags & Passive) !== NoFlags) {
    if (!rootDoesHavePassiveEffect) {
      rootDoesHavePassiveEffect = true;
      scheduleCallback(NormalSchedulerPriority, flushPassiveEffect);
    }
  }
  const subtreeHasEffects = (finishedWork.subtreeFlags & MutationMask) !== NoFlags;
  const rootHasEffect = (finishedWork.flags & MutationMask) !== NoFlags;
  if (subtreeHasEffects || rootHasEffect) {
    commitMutationEffectsOnFiber(finishedWork, root);
    commitLayoutEffects(finishedWork, root);
    if (rootDoesHavePassiveEffect) {
      rootDoesHavePassiveEffect = false;
      rootWithPendingPassiveEffects = root;
    }
  }
  root.current = finishedWork;
}

react-reconciler/src/ReactFiberHooks.js

js
import { scheduleUpdateOnFiber, requestUpdateLane } from "./ReactFiberWorkLoop";
import { NoLane, NoLanes } from './ReactFiberLane';
diff
function dispatchSetState(fiber, queue, action) {
+  const lane = requestUpdateLane();
  const update = {
+   lane,
    action,
    hasEagerState: false,
    eagerState: null,
    next: null
  }
+ const alternate = fiber.alternate;
+  if (fiber.lanes === NoLanes && (alternate === null || alternate.lanes == NoLanes)) {
    const { lastRenderedReducer, lastRenderedState } = queue;
    const eagerState = lastRenderedReducer(lastRenderedState, action);
    update.hasEagerState = true;
    update.eagerState = eagerState;
    if (Object.is(eagerState, lastRenderedState)) {
      return;
    }
+  }
+  const root = enqueueConcurrentHookUpdate(fiber, queue, update, lane);
+  scheduleUpdateOnFiber(root, fiber, lane);
}
diff
function mountReducer(reducer, initialArg) {
  const hook = mountWorkInProgressHook();
  hook.memoizedState = initialArg;
  const queue = {
    pending: null,
    dispatch: null,
+   lastRenderedReducer: reducer,
+   lastRenderedState: initialArg
  }
  hook.queue = queue;
  const dispatch = (queue.dispatch = dispatchReducerAction.bind(null, currentlyRenderingFiber, queue));
  return [hook.memoizedState, dispatch];
}

基于 VitePress 构建