requestUpdateLane
laneを取得する。transitionだったりReact内部で発生したものかブラウザイベント由来かとかで処理が変わる。
sync: SyncLane
renderPhaseUpdate: arbitraryLane
transition: 同一event内の同一優先度のアップデートには、同一のlaneが割り振られる
inside React methods: getCurrentUpdatePriority()
outside React: getCurrentEventPriority;
1. modeがsync → syncLane
2. render phase update → 任意のlaneを取得(でも最高優先度のlaneを取得しているのが重要じゃない?)
3. transitionであれば → transitionLanesから一つ選ぶ(同一イベント由来の更新は同じlaneになるようキャッシュ)
4. React内部由来の更新(flushSyncなど) → 固有のlane
5. React外部の更新 → イベント種類ごとの優先度に応じたlane
createRoot().render()は4にひっかからず、5で処理され、DefaultEventPriorityを得る
code:js
var currentEvent = window.event;
if (currentEvent === undefined) {
return DefaultEventPriority;
}
トランジションでは、同一のイベントの更新中で同じレーンを返すようになっている。
code:js
// The algorithm for assigning an update to a lane should be stable for all
// updates at the same priority within the same event. To do this, the
// inputs to the algorithm must be the same.
//
// The trick we use is to cache the first of each of these inputs within an
// event. Then reset the cached values once we can be sure the event is
// over. Our heuristic for that is whenever we enter a concurrent work loop.
if (currentEventTransitionLane === NoLane) {
// All transitions within the same event are assigned the same lane.
currentEventTransitionLane = claimNextTransitionLane();
}
return currentEventTransitionLane;
このキャッシュは、performConcurrentWorkOnRootでリセットされるため、レンダーフェーズが始まるたびにリセットされる。
code:js
function performConcurrentWorkOnRoot(root, didTimeout) {
// Since we know we're in a React event, we can clear the current
// event time. The next update will compute a new event time.
currentEventTime = NoTimestamp;
currentEventTransitionLane = NoLanes;
code:js
export function requestUpdateLane(fiber: Fiber): Lane {
// Special cases
const mode = fiber.mode;
if ((mode & ConcurrentMode) === NoMode) {
return (SyncLane: Lane);
} else if (
!deferRenderPhaseUpdateToNextBatch &&
(executionContext & RenderContext) !== NoContext &&
workInProgressRootRenderLanes !== NoLanes
) {
// This is a render phase update. These are not officially supported. The
// old behavior is to give this the same "thread" (lanes) as
// whatever is currently rendering. So if you call setState on a component
// that happens later in the same render, it will flush. Ideally, we want to
// remove the special case and treat them as if they came from an
// interleaved event. Regardless, this pattern is not officially supported.
// This behavior is only a fallback. The flag only exists until we can roll
// out the setState warning, since existing code might accidentally rely on
// the current behavior.
return pickArbitraryLane(workInProgressRootRenderLanes);
}
const isTransition = requestCurrentTransition() !== NoTransition;
if (isTransition) {
if (__DEV__ && ReactCurrentBatchConfig.transition !== null) {
const transition = ReactCurrentBatchConfig.transition;
if (!transition._updatedFibers) {
transition._updatedFibers = new Set();
}
transition._updatedFibers.add(fiber);
}
// The algorithm for assigning an update to a lane should be stable for all
// updates at the same priority within the same event. To do this, the
// inputs to the algorithm must be the same.
//
// The trick we use is to cache the first of each of these inputs within an
// event. Then reset the cached values once we can be sure the event is
// over. Our heuristic for that is whenever we enter a concurrent work loop.
if (currentEventTransitionLane === NoLane) {
// All transitions within the same event are assigned the same lane.
currentEventTransitionLane = claimNextTransitionLane();
}
return currentEventTransitionLane;
}
// Updates originating inside certain React methods, like flushSync, have
// their priority set by tracking it with a context variable.
//
// The opaque type returned by the host config is internally a lane, so we can
// use that directly.
// TODO: Move this type conversion to the event priority module.
const updateLane: Lane = (getCurrentUpdatePriority(): any);
if (updateLane !== NoLane) {
return updateLane;
}
// This update originated outside React. Ask the host environment for an
// appropriate priority, based on the type of event.
//
// The opaque type returned by the host config is internally a lane, so we can
// use that directly.
// TODO: Move this type conversion to the event priority module.
const eventLane: Lane = (getCurrentEventPriority(): any);
return eventLane;
}