diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.js
index 65e4188dc9c44..c087ec93765c8 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.js
@@ -1306,44 +1306,25 @@ describe('ReactDOMServerHooks', () => {
// State update should trigger the ID to update, which changes the props
// of ChildWithID. This should cause ChildWithID to hydrate before Children
- gate(flags => {
- if (__DEV__) {
- expect(Scheduler).toFlushAndYieldThrough([
- 'Child with ID',
- // Fallbacks are immdiately committed in TestUtils version
- // of act
- // 'Child with ID',
- // 'Child with ID',
- 'Child One',
- 'Child Two',
- ]);
- } else if (flags.new) {
- // Upgrading a dehyrdating boundary works a little differently in
- // the new reconciler. After the update on the boundary is
- // scheduled, it waits until the end of the current time slice
- // before restarting at the higher priority.
- expect(Scheduler).toFlushAndYieldThrough([
- 'Child with ID',
- 'Child with ID',
- 'Child with ID',
- 'Child with ID',
- 'Child One',
- 'Child Two',
- ]);
- } else {
- // Whereas the old reconciler relies on a Scheduler hack to
- // interrupt the current task. It's not clear if this is any
- // better or worse, though. Regardless it's not a big deal since
- // the time slices aren't that big.
- expect(Scheduler).toFlushAndYieldThrough([
- 'Child with ID',
- 'Child with ID',
- 'Child with ID',
- 'Child One',
- 'Child Two',
- ]);
- }
- });
+ expect(Scheduler).toFlushAndYieldThrough(
+ __DEV__
+ ? [
+ 'Child with ID',
+ // Fallbacks are immediately committed in TestUtils version
+ // of act
+ // 'Child with ID',
+ // 'Child with ID',
+ 'Child One',
+ 'Child Two',
+ ]
+ : [
+ 'Child with ID',
+ 'Child with ID',
+ 'Child with ID',
+ 'Child One',
+ 'Child Two',
+ ],
+ );
expect(child1Ref.current).toBe(null);
expect(childWithIDRef.current).toEqual(
@@ -1691,15 +1672,24 @@ describe('ReactDOMServerHooks', () => {
ReactDOM.createRoot(container, {hydrate: true}).render();
- expect(() =>
- expect(() => Scheduler.unstable_flushAll()).toThrow(
+ if (gate(flags => flags.new)) {
+ expect(() => Scheduler.unstable_flushAll()).toErrorDev([
'The object passed back from useOpaqueIdentifier is meant to be passed through to attributes only. ' +
'Do not read the value directly.',
- ),
- ).toErrorDev([
- 'The object passed back from useOpaqueIdentifier is meant to be passed through to attributes only. ' +
- 'Do not read the value directly.',
- ]);
+ ]);
+ } else {
+ // In the old reconciler, the error isn't surfaced to the user. That
+ // part isn't important, as long as It warns.
+ expect(() =>
+ expect(() => Scheduler.unstable_flushAll()).toThrow(
+ 'The object passed back from useOpaqueIdentifier is meant to be passed through to attributes only. ' +
+ 'Do not read the value directly.',
+ ),
+ ).toErrorDev([
+ 'The object passed back from useOpaqueIdentifier is meant to be passed through to attributes only. ' +
+ 'Do not read the value directly.',
+ ]);
+ }
});
it('useOpaqueIdentifier throws if you try to add the result as a number in a child component wrapped in a Suspense', async () => {
@@ -1724,15 +1714,24 @@ describe('ReactDOMServerHooks', () => {
ReactDOM.createRoot(container, {hydrate: true}).render();
- expect(() =>
- expect(() => Scheduler.unstable_flushAll()).toThrow(
+ if (gate(flags => flags.new)) {
+ expect(() => Scheduler.unstable_flushAll()).toErrorDev([
'The object passed back from useOpaqueIdentifier is meant to be passed through to attributes only. ' +
'Do not read the value directly.',
- ),
- ).toErrorDev([
- 'The object passed back from useOpaqueIdentifier is meant to be passed through to attributes only. ' +
- 'Do not read the value directly.',
- ]);
+ ]);
+ } else {
+ // In the old reconciler, the error isn't surfaced to the user. That
+ // part isn't important, as long as It warns.
+ expect(() =>
+ expect(() => Scheduler.unstable_flushAll()).toThrow(
+ 'The object passed back from useOpaqueIdentifier is meant to be passed through to attributes only. ' +
+ 'Do not read the value directly.',
+ ),
+ ).toErrorDev([
+ 'The object passed back from useOpaqueIdentifier is meant to be passed through to attributes only. ' +
+ 'Do not read the value directly.',
+ ]);
+ }
});
it('useOpaqueIdentifier with two opaque identifiers on the same page', () => {
diff --git a/packages/react-reconciler/src/ReactChildFiber.new.js b/packages/react-reconciler/src/ReactChildFiber.new.js
index e993e4d571e8e..5b0e858d6af96 100644
--- a/packages/react-reconciler/src/ReactChildFiber.new.js
+++ b/packages/react-reconciler/src/ReactChildFiber.new.js
@@ -12,7 +12,7 @@ import type {ReactPortal} from 'shared/ReactTypes';
import type {BlockComponent} from 'react/src/ReactBlock';
import type {LazyComponent} from 'react/src/ReactLazy';
import type {Fiber} from './ReactInternalTypes';
-import type {ExpirationTimeOpaque} from './ReactFiberExpirationTime.new';
+import type {Lanes} from './ReactFiberLane';
import getComponentName from 'shared/getComponentName';
import {Placement, Deletion} from './ReactSideEffectTags';
@@ -377,15 +377,11 @@ function ChildReconciler(shouldTrackSideEffects) {
returnFiber: Fiber,
current: Fiber | null,
textContent: string,
- expirationTime: ExpirationTimeOpaque,
+ lanes: Lanes,
) {
if (current === null || current.tag !== HostText) {
// Insert
- const created = createFiberFromText(
- textContent,
- returnFiber.mode,
- expirationTime,
- );
+ const created = createFiberFromText(textContent, returnFiber.mode, lanes);
created.return = returnFiber;
return created;
} else {
@@ -400,7 +396,7 @@ function ChildReconciler(shouldTrackSideEffects) {
returnFiber: Fiber,
current: Fiber | null,
element: ReactElement,
- expirationTime: ExpirationTimeOpaque,
+ lanes: Lanes,
): Fiber {
if (current !== null) {
if (
@@ -442,11 +438,7 @@ function ChildReconciler(shouldTrackSideEffects) {
}
}
// Insert
- const created = createFiberFromElement(
- element,
- returnFiber.mode,
- expirationTime,
- );
+ const created = createFiberFromElement(element, returnFiber.mode, lanes);
created.ref = coerceRef(returnFiber, current, element);
created.return = returnFiber;
return created;
@@ -456,7 +448,7 @@ function ChildReconciler(shouldTrackSideEffects) {
returnFiber: Fiber,
current: Fiber | null,
portal: ReactPortal,
- expirationTime: ExpirationTimeOpaque,
+ lanes: Lanes,
): Fiber {
if (
current === null ||
@@ -465,11 +457,7 @@ function ChildReconciler(shouldTrackSideEffects) {
current.stateNode.implementation !== portal.implementation
) {
// Insert
- const created = createFiberFromPortal(
- portal,
- returnFiber.mode,
- expirationTime,
- );
+ const created = createFiberFromPortal(portal, returnFiber.mode, lanes);
created.return = returnFiber;
return created;
} else {
@@ -484,7 +472,7 @@ function ChildReconciler(shouldTrackSideEffects) {
returnFiber: Fiber,
current: Fiber | null,
fragment: Iterable<*>,
- expirationTime: ExpirationTimeOpaque,
+ lanes: Lanes,
key: null | string,
): Fiber {
if (current === null || current.tag !== Fragment) {
@@ -492,7 +480,7 @@ function ChildReconciler(shouldTrackSideEffects) {
const created = createFiberFromFragment(
fragment,
returnFiber.mode,
- expirationTime,
+ lanes,
key,
);
created.return = returnFiber;
@@ -508,7 +496,7 @@ function ChildReconciler(shouldTrackSideEffects) {
function createChild(
returnFiber: Fiber,
newChild: any,
- expirationTime: ExpirationTimeOpaque,
+ lanes: Lanes,
): Fiber | null {
if (typeof newChild === 'string' || typeof newChild === 'number') {
// Text nodes don't have keys. If the previous node is implicitly keyed
@@ -517,7 +505,7 @@ function ChildReconciler(shouldTrackSideEffects) {
const created = createFiberFromText(
'' + newChild,
returnFiber.mode,
- expirationTime,
+ lanes,
);
created.return = returnFiber;
return created;
@@ -529,7 +517,7 @@ function ChildReconciler(shouldTrackSideEffects) {
const created = createFiberFromElement(
newChild,
returnFiber.mode,
- expirationTime,
+ lanes,
);
created.ref = coerceRef(returnFiber, null, newChild);
created.return = returnFiber;
@@ -539,7 +527,7 @@ function ChildReconciler(shouldTrackSideEffects) {
const created = createFiberFromPortal(
newChild,
returnFiber.mode,
- expirationTime,
+ lanes,
);
created.return = returnFiber;
return created;
@@ -550,7 +538,7 @@ function ChildReconciler(shouldTrackSideEffects) {
const created = createFiberFromFragment(
newChild,
returnFiber.mode,
- expirationTime,
+ lanes,
null,
);
created.return = returnFiber;
@@ -573,7 +561,7 @@ function ChildReconciler(shouldTrackSideEffects) {
returnFiber: Fiber,
oldFiber: Fiber | null,
newChild: any,
- expirationTime: ExpirationTimeOpaque,
+ lanes: Lanes,
): Fiber | null {
// Update the fiber if the keys match, otherwise return null.
@@ -586,12 +574,7 @@ function ChildReconciler(shouldTrackSideEffects) {
if (key !== null) {
return null;
}
- return updateTextNode(
- returnFiber,
- oldFiber,
- '' + newChild,
- expirationTime,
- );
+ return updateTextNode(returnFiber, oldFiber, '' + newChild, lanes);
}
if (typeof newChild === 'object' && newChild !== null) {
@@ -603,28 +586,18 @@ function ChildReconciler(shouldTrackSideEffects) {
returnFiber,
oldFiber,
newChild.props.children,
- expirationTime,
+ lanes,
key,
);
}
- return updateElement(
- returnFiber,
- oldFiber,
- newChild,
- expirationTime,
- );
+ return updateElement(returnFiber, oldFiber, newChild, lanes);
} else {
return null;
}
}
case REACT_PORTAL_TYPE: {
if (newChild.key === key) {
- return updatePortal(
- returnFiber,
- oldFiber,
- newChild,
- expirationTime,
- );
+ return updatePortal(returnFiber, oldFiber, newChild, lanes);
} else {
return null;
}
@@ -636,13 +609,7 @@ function ChildReconciler(shouldTrackSideEffects) {
return null;
}
- return updateFragment(
- returnFiber,
- oldFiber,
- newChild,
- expirationTime,
- null,
- );
+ return updateFragment(returnFiber, oldFiber, newChild, lanes, null);
}
throwOnInvalidObjectType(returnFiber, newChild);
@@ -662,18 +629,13 @@ function ChildReconciler(shouldTrackSideEffects) {
returnFiber: Fiber,
newIdx: number,
newChild: any,
- expirationTime: ExpirationTimeOpaque,
+ lanes: Lanes,
): Fiber | null {
if (typeof newChild === 'string' || typeof newChild === 'number') {
// Text nodes don't have keys, so we neither have to check the old nor
// new node for the key. If both are text nodes, they match.
const matchedFiber = existingChildren.get(newIdx) || null;
- return updateTextNode(
- returnFiber,
- matchedFiber,
- '' + newChild,
- expirationTime,
- );
+ return updateTextNode(returnFiber, matchedFiber, '' + newChild, lanes);
}
if (typeof newChild === 'object' && newChild !== null) {
@@ -688,40 +650,24 @@ function ChildReconciler(shouldTrackSideEffects) {
returnFiber,
matchedFiber,
newChild.props.children,
- expirationTime,
+ lanes,
newChild.key,
);
}
- return updateElement(
- returnFiber,
- matchedFiber,
- newChild,
- expirationTime,
- );
+ return updateElement(returnFiber, matchedFiber, newChild, lanes);
}
case REACT_PORTAL_TYPE: {
const matchedFiber =
existingChildren.get(
newChild.key === null ? newIdx : newChild.key,
) || null;
- return updatePortal(
- returnFiber,
- matchedFiber,
- newChild,
- expirationTime,
- );
+ return updatePortal(returnFiber, matchedFiber, newChild, lanes);
}
}
if (isArray(newChild) || getIteratorFn(newChild)) {
const matchedFiber = existingChildren.get(newIdx) || null;
- return updateFragment(
- returnFiber,
- matchedFiber,
- newChild,
- expirationTime,
- null,
- );
+ return updateFragment(returnFiber, matchedFiber, newChild, lanes, null);
}
throwOnInvalidObjectType(returnFiber, newChild);
@@ -785,7 +731,7 @@ function ChildReconciler(shouldTrackSideEffects) {
returnFiber: Fiber,
currentFirstChild: Fiber | null,
newChildren: Array<*>,
- expirationTime: ExpirationTimeOpaque,
+ lanes: Lanes,
): Fiber | null {
// This algorithm can't optimize by searching from both ends since we
// don't have backpointers on fibers. I'm trying to see how far we can get
@@ -833,7 +779,7 @@ function ChildReconciler(shouldTrackSideEffects) {
returnFiber,
oldFiber,
newChildren[newIdx],
- expirationTime,
+ lanes,
);
if (newFiber === null) {
// TODO: This breaks on empty slots like null children. That's
@@ -877,11 +823,7 @@ function ChildReconciler(shouldTrackSideEffects) {
// If we don't have any more existing children we can choose a fast path
// since the rest will all be insertions.
for (; newIdx < newChildren.length; newIdx++) {
- const newFiber = createChild(
- returnFiber,
- newChildren[newIdx],
- expirationTime,
- );
+ const newFiber = createChild(returnFiber, newChildren[newIdx], lanes);
if (newFiber === null) {
continue;
}
@@ -907,7 +849,7 @@ function ChildReconciler(shouldTrackSideEffects) {
returnFiber,
newIdx,
newChildren[newIdx],
- expirationTime,
+ lanes,
);
if (newFiber !== null) {
if (shouldTrackSideEffects) {
@@ -944,7 +886,7 @@ function ChildReconciler(shouldTrackSideEffects) {
returnFiber: Fiber,
currentFirstChild: Fiber | null,
newChildrenIterable: Iterable<*>,
- expirationTime: ExpirationTimeOpaque,
+ lanes: Lanes,
): Fiber | null {
// This is the same implementation as reconcileChildrenArray(),
// but using the iterator instead.
@@ -1023,12 +965,7 @@ function ChildReconciler(shouldTrackSideEffects) {
} else {
nextOldFiber = oldFiber.sibling;
}
- const newFiber = updateSlot(
- returnFiber,
- oldFiber,
- step.value,
- expirationTime,
- );
+ const newFiber = updateSlot(returnFiber, oldFiber, step.value, lanes);
if (newFiber === null) {
// TODO: This breaks on empty slots like null children. That's
// unfortunate because it triggers the slow path all the time. We need
@@ -1071,7 +1008,7 @@ function ChildReconciler(shouldTrackSideEffects) {
// If we don't have any more existing children we can choose a fast path
// since the rest will all be insertions.
for (; !step.done; newIdx++, step = newChildren.next()) {
- const newFiber = createChild(returnFiber, step.value, expirationTime);
+ const newFiber = createChild(returnFiber, step.value, lanes);
if (newFiber === null) {
continue;
}
@@ -1097,7 +1034,7 @@ function ChildReconciler(shouldTrackSideEffects) {
returnFiber,
newIdx,
step.value,
- expirationTime,
+ lanes,
);
if (newFiber !== null) {
if (shouldTrackSideEffects) {
@@ -1134,7 +1071,7 @@ function ChildReconciler(shouldTrackSideEffects) {
returnFiber: Fiber,
currentFirstChild: Fiber | null,
textContent: string,
- expirationTime: ExpirationTimeOpaque,
+ lanes: Lanes,
): Fiber {
// There's no need to check for keys on text nodes since we don't have a
// way to define them.
@@ -1149,11 +1086,7 @@ function ChildReconciler(shouldTrackSideEffects) {
// The existing first child is not a text node so we need to create one
// and delete the existing ones.
deleteRemainingChildren(returnFiber, currentFirstChild);
- const created = createFiberFromText(
- textContent,
- returnFiber.mode,
- expirationTime,
- );
+ const created = createFiberFromText(textContent, returnFiber.mode, lanes);
created.return = returnFiber;
return created;
}
@@ -1162,7 +1095,7 @@ function ChildReconciler(shouldTrackSideEffects) {
returnFiber: Fiber,
currentFirstChild: Fiber | null,
element: ReactElement,
- expirationTime: ExpirationTimeOpaque,
+ lanes: Lanes,
): Fiber {
const key = element.key;
let child = currentFirstChild;
@@ -1245,17 +1178,13 @@ function ChildReconciler(shouldTrackSideEffects) {
const created = createFiberFromFragment(
element.props.children,
returnFiber.mode,
- expirationTime,
+ lanes,
element.key,
);
created.return = returnFiber;
return created;
} else {
- const created = createFiberFromElement(
- element,
- returnFiber.mode,
- expirationTime,
- );
+ const created = createFiberFromElement(element, returnFiber.mode, lanes);
created.ref = coerceRef(returnFiber, currentFirstChild, element);
created.return = returnFiber;
return created;
@@ -1266,7 +1195,7 @@ function ChildReconciler(shouldTrackSideEffects) {
returnFiber: Fiber,
currentFirstChild: Fiber | null,
portal: ReactPortal,
- expirationTime: ExpirationTimeOpaque,
+ lanes: Lanes,
): Fiber {
const key = portal.key;
let child = currentFirstChild;
@@ -1293,11 +1222,7 @@ function ChildReconciler(shouldTrackSideEffects) {
child = child.sibling;
}
- const created = createFiberFromPortal(
- portal,
- returnFiber.mode,
- expirationTime,
- );
+ const created = createFiberFromPortal(portal, returnFiber.mode, lanes);
created.return = returnFiber;
return created;
}
@@ -1309,7 +1234,7 @@ function ChildReconciler(shouldTrackSideEffects) {
returnFiber: Fiber,
currentFirstChild: Fiber | null,
newChild: any,
- expirationTime: ExpirationTimeOpaque,
+ lanes: Lanes,
): Fiber | null {
// This function is not recursive.
// If the top level item is an array, we treat it as a set of children,
@@ -1339,7 +1264,7 @@ function ChildReconciler(shouldTrackSideEffects) {
returnFiber,
currentFirstChild,
newChild,
- expirationTime,
+ lanes,
),
);
case REACT_PORTAL_TYPE:
@@ -1348,7 +1273,7 @@ function ChildReconciler(shouldTrackSideEffects) {
returnFiber,
currentFirstChild,
newChild,
- expirationTime,
+ lanes,
),
);
}
@@ -1360,7 +1285,7 @@ function ChildReconciler(shouldTrackSideEffects) {
returnFiber,
currentFirstChild,
'' + newChild,
- expirationTime,
+ lanes,
),
);
}
@@ -1370,7 +1295,7 @@ function ChildReconciler(shouldTrackSideEffects) {
returnFiber,
currentFirstChild,
newChild,
- expirationTime,
+ lanes,
);
}
@@ -1379,7 +1304,7 @@ function ChildReconciler(shouldTrackSideEffects) {
returnFiber,
currentFirstChild,
newChild,
- expirationTime,
+ lanes,
);
}
@@ -1462,13 +1387,10 @@ export function cloneChildFibers(
}
// Reset a workInProgress child set to prepare it for a second pass.
-export function resetChildFibers(
- workInProgress: Fiber,
- renderExpirationTime: ExpirationTimeOpaque,
-): void {
+export function resetChildFibers(workInProgress: Fiber, lanes: Lanes): void {
let child = workInProgress.child;
while (child !== null) {
- resetWorkInProgress(child, renderExpirationTime);
+ resetWorkInProgress(child, lanes);
child = child.sibling;
}
}
diff --git a/packages/react-reconciler/src/ReactFiber.new.js b/packages/react-reconciler/src/ReactFiber.new.js
index 741083a8650cc..b428e11374f43 100644
--- a/packages/react-reconciler/src/ReactFiber.new.js
+++ b/packages/react-reconciler/src/ReactFiber.new.js
@@ -18,7 +18,7 @@ import type {Fiber} from './ReactInternalTypes';
import type {RootTag} from './ReactRootTags';
import type {WorkTag} from './ReactWorkTags';
import type {TypeOfMode} from './ReactTypeOfMode';
-import type {ExpirationTimeOpaque} from './ReactFiberExpirationTime.new';
+import type {Lanes} from './ReactFiberLane';
import type {SuspenseInstance} from './ReactFiberHostConfig';
import type {OffscreenProps} from './ReactFiberOffscreenComponent';
@@ -66,7 +66,7 @@ import {
resolveFunctionForHotReloading,
resolveForwardRefForHotReloading,
} from './ReactFiberHotReloading.new';
-import {NoWork} from './ReactFiberExpirationTime.new';
+import {NoLanes} from './ReactFiberLane';
import {
NoMode,
ConcurrentMode,
@@ -150,8 +150,8 @@ function FiberNode(
this.firstEffect = null;
this.lastEffect = null;
- this.expirationTime_opaque = NoWork;
- this.childExpirationTime_opaque = NoWork;
+ this.lanes = NoLanes;
+ this.childLanes = NoLanes;
this.alternate = null;
@@ -314,9 +314,8 @@ export function createWorkInProgress(current: Fiber, pendingProps: any): Fiber {
}
}
- workInProgress.childExpirationTime_opaque =
- current.childExpirationTime_opaque;
- workInProgress.expirationTime_opaque = current.expirationTime_opaque;
+ workInProgress.childLanes = current.childLanes;
+ workInProgress.lanes = current.lanes;
workInProgress.child = current.child;
workInProgress.memoizedProps = current.memoizedProps;
@@ -330,7 +329,7 @@ export function createWorkInProgress(current: Fiber, pendingProps: any): Fiber {
currentDependencies === null
? null
: {
- expirationTime: currentDependencies.expirationTime,
+ lanes: currentDependencies.lanes,
firstContext: currentDependencies.firstContext,
responders: currentDependencies.responders,
};
@@ -368,10 +367,7 @@ export function createWorkInProgress(current: Fiber, pendingProps: any): Fiber {
}
// Used to reuse a Fiber for a second pass.
-export function resetWorkInProgress(
- workInProgress: Fiber,
- renderExpirationTime: ExpirationTimeOpaque,
-) {
+export function resetWorkInProgress(workInProgress: Fiber, renderLanes: Lanes) {
// This resets the Fiber to what createFiber or createWorkInProgress would
// have set the values to before during the first pass. Ideally this wouldn't
// be necessary but unfortunately many code paths reads from the workInProgress
@@ -392,8 +388,8 @@ export function resetWorkInProgress(
const current = workInProgress.alternate;
if (current === null) {
// Reset to createFiber's initial values.
- workInProgress.childExpirationTime_opaque = NoWork;
- workInProgress.expirationTime_opaque = renderExpirationTime;
+ workInProgress.childLanes = NoLanes;
+ workInProgress.lanes = renderLanes;
workInProgress.child = null;
workInProgress.memoizedProps = null;
@@ -412,9 +408,8 @@ export function resetWorkInProgress(
}
} else {
// Reset to the cloned values that createWorkInProgress would've.
- workInProgress.childExpirationTime_opaque =
- current.childExpirationTime_opaque;
- workInProgress.expirationTime_opaque = current.expirationTime_opaque;
+ workInProgress.childLanes = current.childLanes;
+ workInProgress.lanes = current.lanes;
workInProgress.child = current.child;
workInProgress.memoizedProps = current.memoizedProps;
@@ -428,7 +423,7 @@ export function resetWorkInProgress(
currentDependencies === null
? null
: {
- expirationTime: currentDependencies.expirationTime,
+ lanes: currentDependencies.lanes,
firstContext: currentDependencies.firstContext,
responders: currentDependencies.responders,
};
@@ -470,7 +465,7 @@ export function createFiberFromTypeAndProps(
pendingProps: any,
owner: null | Fiber,
mode: TypeOfMode,
- expirationTime: ExpirationTimeOpaque,
+ lanes: Lanes,
): Fiber {
let fiberTag = IndeterminateComponent;
// The resolved type is set if we know what the final type will be. I.e. it's not lazy.
@@ -491,12 +486,7 @@ export function createFiberFromTypeAndProps(
} else {
getTag: switch (type) {
case REACT_FRAGMENT_TYPE:
- return createFiberFromFragment(
- pendingProps.children,
- mode,
- expirationTime,
- key,
- );
+ return createFiberFromFragment(pendingProps.children, mode, lanes, key);
case REACT_DEBUG_TRACING_MODE_TYPE:
fiberTag = Mode;
mode |= DebugTracingMode;
@@ -506,30 +496,16 @@ export function createFiberFromTypeAndProps(
mode |= StrictMode;
break;
case REACT_PROFILER_TYPE:
- return createFiberFromProfiler(pendingProps, mode, expirationTime, key);
+ return createFiberFromProfiler(pendingProps, mode, lanes, key);
case REACT_SUSPENSE_TYPE:
- return createFiberFromSuspense(pendingProps, mode, expirationTime, key);
+ return createFiberFromSuspense(pendingProps, mode, lanes, key);
case REACT_SUSPENSE_LIST_TYPE:
- return createFiberFromSuspenseList(
- pendingProps,
- mode,
- expirationTime,
- key,
- );
+ return createFiberFromSuspenseList(pendingProps, mode, lanes, key);
case REACT_OFFSCREEN_TYPE:
- return createFiberFromOffscreen(
- pendingProps,
- mode,
- expirationTime,
- key,
- );
+ return createFiberFromOffscreen(pendingProps, mode, lanes, key);
case REACT_LEGACY_HIDDEN_TYPE:
- return createFiberFromLegacyHidden(
- pendingProps,
- mode,
- expirationTime,
- key,
- );
+ return createFiberFromLegacyHidden(pendingProps, mode, lanes, key);
+
default: {
if (typeof type === 'object' && type !== null) {
switch (type.$$typeof) {
@@ -562,7 +538,7 @@ export function createFiberFromTypeAndProps(
type,
pendingProps,
mode,
- expirationTime,
+ lanes,
key,
);
}
@@ -573,7 +549,7 @@ export function createFiberFromTypeAndProps(
type,
pendingProps,
mode,
- expirationTime,
+ lanes,
key,
);
}
@@ -612,7 +588,7 @@ export function createFiberFromTypeAndProps(
const fiber = createFiber(fiberTag, pendingProps, key, mode);
fiber.elementType = type;
fiber.type = resolvedType;
- fiber.expirationTime_opaque = expirationTime;
+ fiber.lanes = lanes;
return fiber;
}
@@ -620,7 +596,7 @@ export function createFiberFromTypeAndProps(
export function createFiberFromElement(
element: ReactElement,
mode: TypeOfMode,
- expirationTime: ExpirationTimeOpaque,
+ lanes: Lanes,
): Fiber {
let owner = null;
if (__DEV__) {
@@ -635,7 +611,7 @@ export function createFiberFromElement(
pendingProps,
owner,
mode,
- expirationTime,
+ lanes,
);
if (__DEV__) {
fiber._debugSource = element._source;
@@ -647,11 +623,11 @@ export function createFiberFromElement(
export function createFiberFromFragment(
elements: ReactFragment,
mode: TypeOfMode,
- expirationTime: ExpirationTimeOpaque,
+ lanes: Lanes,
key: null | string,
): Fiber {
const fiber = createFiber(Fragment, elements, key, mode);
- fiber.expirationTime_opaque = expirationTime;
+ fiber.lanes = lanes;
return fiber;
}
@@ -659,13 +635,13 @@ export function createFiberFromFundamental(
fundamentalComponent: ReactFundamentalComponent,
pendingProps: any,
mode: TypeOfMode,
- expirationTime: ExpirationTimeOpaque,
+ lanes: Lanes,
key: null | string,
): Fiber {
const fiber = createFiber(FundamentalComponent, pendingProps, key, mode);
fiber.elementType = fundamentalComponent;
fiber.type = fundamentalComponent;
- fiber.expirationTime_opaque = expirationTime;
+ fiber.lanes = lanes;
return fiber;
}
@@ -673,20 +649,20 @@ function createFiberFromScope(
scope: ReactScope,
pendingProps: any,
mode: TypeOfMode,
- expirationTime: ExpirationTimeOpaque,
+ lanes: Lanes,
key: null | string,
) {
const fiber = createFiber(ScopeComponent, pendingProps, key, mode);
fiber.type = scope;
fiber.elementType = scope;
- fiber.expirationTime_opaque = expirationTime;
+ fiber.lanes = lanes;
return fiber;
}
function createFiberFromProfiler(
pendingProps: any,
mode: TypeOfMode,
- expirationTime: ExpirationTimeOpaque,
+ lanes: Lanes,
key: null | string,
): Fiber {
if (__DEV__) {
@@ -699,7 +675,7 @@ function createFiberFromProfiler(
// TODO: The Profiler fiber shouldn't have a type. It has a tag.
fiber.elementType = REACT_PROFILER_TYPE;
fiber.type = REACT_PROFILER_TYPE;
- fiber.expirationTime_opaque = expirationTime;
+ fiber.lanes = lanes;
if (enableProfilerTimer) {
fiber.stateNode = {
@@ -714,7 +690,7 @@ function createFiberFromProfiler(
export function createFiberFromSuspense(
pendingProps: any,
mode: TypeOfMode,
- expirationTime: ExpirationTimeOpaque,
+ lanes: Lanes,
key: null | string,
) {
const fiber = createFiber(SuspenseComponent, pendingProps, key, mode);
@@ -725,14 +701,14 @@ export function createFiberFromSuspense(
fiber.type = REACT_SUSPENSE_TYPE;
fiber.elementType = REACT_SUSPENSE_TYPE;
- fiber.expirationTime_opaque = expirationTime;
+ fiber.lanes = lanes;
return fiber;
}
export function createFiberFromSuspenseList(
pendingProps: any,
mode: TypeOfMode,
- expirationTime: ExpirationTimeOpaque,
+ lanes: Lanes,
key: null | string,
) {
const fiber = createFiber(SuspenseListComponent, pendingProps, key, mode);
@@ -743,14 +719,14 @@ export function createFiberFromSuspenseList(
fiber.type = REACT_SUSPENSE_LIST_TYPE;
}
fiber.elementType = REACT_SUSPENSE_LIST_TYPE;
- fiber.expirationTime_opaque = expirationTime;
+ fiber.lanes = lanes;
return fiber;
}
export function createFiberFromOffscreen(
pendingProps: OffscreenProps,
mode: TypeOfMode,
- expirationTime: ExpirationTimeOpaque,
+ lanes: Lanes,
key: null | string,
) {
const fiber = createFiber(OffscreenComponent, pendingProps, key, mode);
@@ -761,14 +737,14 @@ export function createFiberFromOffscreen(
fiber.type = REACT_OFFSCREEN_TYPE;
}
fiber.elementType = REACT_OFFSCREEN_TYPE;
- fiber.expirationTime_opaque = expirationTime;
+ fiber.lanes = lanes;
return fiber;
}
export function createFiberFromLegacyHidden(
pendingProps: OffscreenProps,
mode: TypeOfMode,
- expirationTime: ExpirationTimeOpaque,
+ lanes: Lanes,
key: null | string,
) {
const fiber = createFiber(LegacyHiddenComponent, pendingProps, key, mode);
@@ -779,17 +755,17 @@ export function createFiberFromLegacyHidden(
fiber.type = REACT_LEGACY_HIDDEN_TYPE;
}
fiber.elementType = REACT_LEGACY_HIDDEN_TYPE;
- fiber.expirationTime_opaque = expirationTime;
+ fiber.lanes = lanes;
return fiber;
}
export function createFiberFromText(
content: string,
mode: TypeOfMode,
- expirationTime: ExpirationTimeOpaque,
+ lanes: Lanes,
): Fiber {
const fiber = createFiber(HostText, content, null, mode);
- fiber.expirationTime_opaque = expirationTime;
+ fiber.lanes = lanes;
return fiber;
}
@@ -812,11 +788,11 @@ export function createFiberFromDehydratedFragment(
export function createFiberFromPortal(
portal: ReactPortal,
mode: TypeOfMode,
- expirationTime: ExpirationTimeOpaque,
+ lanes: Lanes,
): Fiber {
const pendingProps = portal.children !== null ? portal.children : [];
const fiber = createFiber(HostPortal, pendingProps, portal.key, mode);
- fiber.expirationTime_opaque = expirationTime;
+ fiber.lanes = lanes;
fiber.stateNode = {
containerInfo: portal.containerInfo,
pendingChildren: null, // Used by persistent updates
@@ -862,8 +838,8 @@ export function assignFiberPropertiesInDEV(
target.nextEffect = source.nextEffect;
target.firstEffect = source.firstEffect;
target.lastEffect = source.lastEffect;
- target.expirationTime_opaque = source.expirationTime_opaque;
- target.childExpirationTime_opaque = source.childExpirationTime_opaque;
+ target.lanes = source.lanes;
+ target.childLanes = source.childLanes;
target.alternate = source.alternate;
if (enableProfilerTimer) {
target.actualDuration = source.actualDuration;
diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.new.js b/packages/react-reconciler/src/ReactFiberBeginWork.new.js
index 576016d2f6945..012976aaf8a81 100644
--- a/packages/react-reconciler/src/ReactFiberBeginWork.new.js
+++ b/packages/react-reconciler/src/ReactFiberBeginWork.new.js
@@ -12,7 +12,7 @@ import type {BlockComponent} from 'react/src/ReactBlock';
import type {LazyComponent as LazyComponentType} from 'react/src/ReactLazy';
import type {Fiber} from './ReactInternalTypes';
import type {FiberRoot} from './ReactInternalTypes';
-import type {ExpirationTimeOpaque} from './ReactFiberExpirationTime.new';
+import type {Lanes, Lane} from './ReactFiberLane';
import type {
SuspenseState,
SuspenseListRenderState,
@@ -107,14 +107,17 @@ import {
initializeUpdateQueue,
} from './ReactUpdateQueue.new';
import {
- NoWork,
- Never,
- Sync,
- DefaultUpdateTime,
- isSameOrHigherPriority,
- isSameExpirationTime,
- bumpPriorityHigher,
-} from './ReactFiberExpirationTime.new';
+ NoLane,
+ NoLanes,
+ SyncLane,
+ OffscreenLane,
+ DefaultHydrationLane,
+ includesSomeLane,
+ laneToLanes,
+ removeLanes,
+ combineLanes,
+ getBumpedLaneForHydration,
+} from './ReactFiberLane';
import {
ConcurrentMode,
NoMode,
@@ -191,9 +194,9 @@ import {
retryDehydratedSuspenseBoundary,
scheduleUpdateOnFiber,
renderDidSuspendDelayIfPossible,
- markUnprocessedUpdateTime,
+ markSkippedUpdateLanes,
getWorkInProgressRoot,
- pushRenderExpirationTime,
+ pushRenderLanes,
} from './ReactFiberWorkLoop.new';
import {disableLogs, reenableLogs} from 'shared/ConsolePatchingDev';
@@ -228,7 +231,7 @@ export function reconcileChildren(
current: Fiber | null,
workInProgress: Fiber,
nextChildren: any,
- renderExpirationTime: ExpirationTimeOpaque,
+ renderLanes: Lanes,
) {
if (current === null) {
// If this is a fresh new component that hasn't been rendered yet, we
@@ -239,7 +242,7 @@ export function reconcileChildren(
workInProgress,
null,
nextChildren,
- renderExpirationTime,
+ renderLanes,
);
} else {
// If the current child is the same as the work in progress, it means that
@@ -252,7 +255,7 @@ export function reconcileChildren(
workInProgress,
current.child,
nextChildren,
- renderExpirationTime,
+ renderLanes,
);
}
}
@@ -261,7 +264,7 @@ function forceUnmountCurrentAndReconcile(
current: Fiber,
workInProgress: Fiber,
nextChildren: any,
- renderExpirationTime: ExpirationTimeOpaque,
+ renderLanes: Lanes,
) {
// This function is fork of reconcileChildren. It's used in cases where we
// want to reconcile without matching against the existing set. This has the
@@ -275,7 +278,7 @@ function forceUnmountCurrentAndReconcile(
workInProgress,
current.child,
null,
- renderExpirationTime,
+ renderLanes,
);
// In the second pass, we mount the new children. The trick here is that we
// pass null in place of where we usually pass the current child set. This has
@@ -285,7 +288,7 @@ function forceUnmountCurrentAndReconcile(
workInProgress,
null,
nextChildren,
- renderExpirationTime,
+ renderLanes,
);
}
@@ -294,7 +297,7 @@ function updateForwardRef(
workInProgress: Fiber,
Component: any,
nextProps: any,
- renderExpirationTime: ExpirationTimeOpaque,
+ renderLanes: Lanes,
) {
// TODO: current can be non-null here even if the component
// hasn't yet mounted. This happens after the first render suspends.
@@ -321,7 +324,7 @@ function updateForwardRef(
// The rest is a fork of updateFunctionComponent
let nextChildren;
- prepareToReadContext(workInProgress, renderExpirationTime);
+ prepareToReadContext(workInProgress, renderLanes);
if (__DEV__) {
ReactCurrentOwner.current = workInProgress;
setIsRendering(true);
@@ -331,7 +334,7 @@ function updateForwardRef(
render,
nextProps,
ref,
- renderExpirationTime,
+ renderLanes,
);
if (
debugRenderPhaseSideEffectsForStrictMode &&
@@ -345,7 +348,7 @@ function updateForwardRef(
render,
nextProps,
ref,
- renderExpirationTime,
+ renderLanes,
);
} finally {
reenableLogs();
@@ -359,27 +362,18 @@ function updateForwardRef(
render,
nextProps,
ref,
- renderExpirationTime,
+ renderLanes,
);
}
if (current !== null && !didReceiveUpdate) {
- bailoutHooks(current, workInProgress, renderExpirationTime);
- return bailoutOnAlreadyFinishedWork(
- current,
- workInProgress,
- renderExpirationTime,
- );
+ bailoutHooks(current, workInProgress, renderLanes);
+ return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);
}
// React DevTools reads this flag.
workInProgress.effectTag |= PerformedWork;
- reconcileChildren(
- current,
- workInProgress,
- nextChildren,
- renderExpirationTime,
- );
+ reconcileChildren(current, workInProgress, nextChildren, renderLanes);
return workInProgress.child;
}
@@ -388,8 +382,8 @@ function updateMemoComponent(
workInProgress: Fiber,
Component: any,
nextProps: any,
- updateExpirationTime,
- renderExpirationTime: ExpirationTimeOpaque,
+ updateLanes: Lanes,
+ renderLanes: Lanes,
): null | Fiber {
if (current === null) {
const type = Component.type;
@@ -416,8 +410,8 @@ function updateMemoComponent(
workInProgress,
resolvedType,
nextProps,
- updateExpirationTime,
- renderExpirationTime,
+ updateLanes,
+ renderLanes,
);
}
if (__DEV__) {
@@ -439,7 +433,7 @@ function updateMemoComponent(
nextProps,
null,
workInProgress.mode,
- renderExpirationTime,
+ renderLanes,
);
child.ref = workInProgress.ref;
child.return = workInProgress;
@@ -461,7 +455,7 @@ function updateMemoComponent(
}
}
const currentChild = ((current.child: any): Fiber); // This is always exactly one child
- if (!isSameOrHigherPriority(updateExpirationTime, renderExpirationTime)) {
+ if (!includesSomeLane(updateLanes, renderLanes)) {
// This will be the props with resolved defaultProps,
// unlike current.memoizedProps which will be the unresolved ones.
const prevProps = currentChild.memoizedProps;
@@ -469,11 +463,7 @@ function updateMemoComponent(
let compare = Component.compare;
compare = compare !== null ? compare : shallowEqual;
if (compare(prevProps, nextProps) && current.ref === workInProgress.ref) {
- return bailoutOnAlreadyFinishedWork(
- current,
- workInProgress,
- renderExpirationTime,
- );
+ return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);
}
}
// React DevTools reads this flag.
@@ -490,8 +480,8 @@ function updateSimpleMemoComponent(
workInProgress: Fiber,
Component: any,
nextProps: any,
- updateExpirationTime,
- renderExpirationTime: ExpirationTimeOpaque,
+ updateLanes: Lanes,
+ renderLanes: Lanes,
): null | Fiber {
// TODO: current can be non-null here even if the component
// hasn't yet mounted. This happens when the inner render suspends.
@@ -536,10 +526,10 @@ function updateSimpleMemoComponent(
(__DEV__ ? workInProgress.type === current.type : true)
) {
didReceiveUpdate = false;
- if (!isSameOrHigherPriority(updateExpirationTime, renderExpirationTime)) {
- // The pending update priority was cleared at the beginning of
- // beginWork. We're about to bail out, but there might be additional
- // updates at a lower priority. Usually, the priority level of the
+ if (!includesSomeLane(renderLanes, updateLanes)) {
+ // The pending lanes were cleared at the beginning of beginWork. We're
+ // about to bail out, but there might be other lanes that weren't
+ // included in the current render. Usually, the priority level of the
// remaining updates is accumlated during the evaluation of the
// component (i.e. when processing the update queue). But since since
// we're bailing out early *without* evaluating the component, we need
@@ -550,11 +540,11 @@ function updateSimpleMemoComponent(
// contains hooks.
// TODO: Move the reset at in beginWork out of the common path so that
// this is no longer necessary.
- workInProgress.expirationTime_opaque = current.expirationTime_opaque;
+ workInProgress.lanes = current.lanes;
return bailoutOnAlreadyFinishedWork(
current,
workInProgress,
- renderExpirationTime,
+ renderLanes,
);
}
}
@@ -564,14 +554,14 @@ function updateSimpleMemoComponent(
workInProgress,
Component,
nextProps,
- renderExpirationTime,
+ renderLanes,
);
}
function updateOffscreenComponent(
current: Fiber | null,
workInProgress: Fiber,
- renderExpirationTime: ExpirationTimeOpaque,
+ renderLanes: Lanes,
) {
const nextProps: OffscreenProps = workInProgress.pendingProps;
const nextChildren = nextProps.children;
@@ -580,71 +570,57 @@ function updateOffscreenComponent(
current !== null ? current.memoizedState : null;
if (nextProps.mode === 'hidden') {
- if (
- !isSameExpirationTime(renderExpirationTime, (Never: ExpirationTimeOpaque))
- ) {
- let nextBaseTime;
+ if (!includesSomeLane(renderLanes, (OffscreenLane: Lane))) {
+ let nextBaseLanes;
if (prevState !== null) {
- const prevBaseTime = prevState.baseTime;
- nextBaseTime = !isSameOrHigherPriority(
- prevBaseTime,
- renderExpirationTime,
- )
- ? prevBaseTime
- : renderExpirationTime;
+ const prevBaseLanes = prevState.baseLanes;
+ nextBaseLanes = combineLanes(prevBaseLanes, renderLanes);
} else {
- nextBaseTime = renderExpirationTime;
+ nextBaseLanes = renderLanes;
}
// Schedule this fiber to re-render at offscreen priority. Then bailout.
if (enableSchedulerTracing) {
- markSpawnedWork((Never: ExpirationTimeOpaque));
+ markSpawnedWork((OffscreenLane: Lane));
}
- workInProgress.expirationTime_opaque = workInProgress.childExpirationTime_opaque = Never;
+ workInProgress.lanes = workInProgress.childLanes = laneToLanes(
+ OffscreenLane,
+ );
const nextState: OffscreenState = {
- baseTime: nextBaseTime,
+ baseLanes: nextBaseLanes,
};
workInProgress.memoizedState = nextState;
// We're about to bail out, but we need to push this to the stack anyway
// to avoid a push/pop misalignment.
- pushRenderExpirationTime(workInProgress, nextBaseTime);
+ pushRenderLanes(workInProgress, nextBaseLanes);
return null;
} else {
- // Rendering at offscreen, so we can clear the base time.
+ // Rendering at offscreen, so we can clear the base lanes.
const nextState: OffscreenState = {
- baseTime: NoWork,
+ baseLanes: NoLanes,
};
workInProgress.memoizedState = nextState;
- pushRenderExpirationTime(workInProgress, renderExpirationTime);
+ // Push the lanes that were skipped when we bailed out.
+ const subtreeRenderLanes =
+ prevState !== null ? prevState.baseLanes : renderLanes;
+ pushRenderLanes(workInProgress, subtreeRenderLanes);
}
} else {
- let subtreeRenderTime;
+ let subtreeRenderLanes;
if (prevState !== null) {
- const baseTime = prevState.baseTime;
- subtreeRenderTime = !isSameOrHigherPriority(
- baseTime,
- renderExpirationTime,
- )
- ? baseTime
- : renderExpirationTime;
-
+ subtreeRenderLanes = combineLanes(prevState.baseLanes, renderLanes);
// Since we're not hidden anymore, reset the state
workInProgress.memoizedState = null;
} else {
// We weren't previously hidden, and we still aren't, so there's nothing
// special to do. Need to push to the stack regardless, though, to avoid
// a push/pop misalignment.
- subtreeRenderTime = renderExpirationTime;
+ subtreeRenderLanes = renderLanes;
}
- pushRenderExpirationTime(workInProgress, subtreeRenderTime);
+ pushRenderLanes(workInProgress, subtreeRenderLanes);
}
- reconcileChildren(
- current,
- workInProgress,
- nextChildren,
- renderExpirationTime,
- );
+ reconcileChildren(current, workInProgress, nextChildren, renderLanes);
return workInProgress.child;
}
@@ -656,37 +632,27 @@ const updateLegacyHiddenComponent = updateOffscreenComponent;
function updateFragment(
current: Fiber | null,
workInProgress: Fiber,
- renderExpirationTime: ExpirationTimeOpaque,
+ renderLanes: Lanes,
) {
const nextChildren = workInProgress.pendingProps;
- reconcileChildren(
- current,
- workInProgress,
- nextChildren,
- renderExpirationTime,
- );
+ reconcileChildren(current, workInProgress, nextChildren, renderLanes);
return workInProgress.child;
}
function updateMode(
current: Fiber | null,
workInProgress: Fiber,
- renderExpirationTime: ExpirationTimeOpaque,
+ renderLanes: Lanes,
) {
const nextChildren = workInProgress.pendingProps.children;
- reconcileChildren(
- current,
- workInProgress,
- nextChildren,
- renderExpirationTime,
- );
+ reconcileChildren(current, workInProgress, nextChildren, renderLanes);
return workInProgress.child;
}
function updateProfiler(
current: Fiber | null,
workInProgress: Fiber,
- renderExpirationTime: ExpirationTimeOpaque,
+ renderLanes: Lanes,
) {
if (enableProfilerTimer) {
workInProgress.effectTag |= Update;
@@ -699,12 +665,7 @@ function updateProfiler(
}
const nextProps = workInProgress.pendingProps;
const nextChildren = nextProps.children;
- reconcileChildren(
- current,
- workInProgress,
- nextChildren,
- renderExpirationTime,
- );
+ reconcileChildren(current, workInProgress, nextChildren, renderLanes);
return workInProgress.child;
}
@@ -724,7 +685,7 @@ function updateFunctionComponent(
workInProgress,
Component,
nextProps: any,
- renderExpirationTime,
+ renderLanes,
) {
if (__DEV__) {
if (workInProgress.type !== workInProgress.elementType) {
@@ -749,7 +710,7 @@ function updateFunctionComponent(
}
let nextChildren;
- prepareToReadContext(workInProgress, renderExpirationTime);
+ prepareToReadContext(workInProgress, renderLanes);
if (__DEV__) {
ReactCurrentOwner.current = workInProgress;
setIsRendering(true);
@@ -759,7 +720,7 @@ function updateFunctionComponent(
Component,
nextProps,
context,
- renderExpirationTime,
+ renderLanes,
);
if (
debugRenderPhaseSideEffectsForStrictMode &&
@@ -773,7 +734,7 @@ function updateFunctionComponent(
Component,
nextProps,
context,
- renderExpirationTime,
+ renderLanes,
);
} finally {
reenableLogs();
@@ -787,27 +748,18 @@ function updateFunctionComponent(
Component,
nextProps,
context,
- renderExpirationTime,
+ renderLanes,
);
}
if (current !== null && !didReceiveUpdate) {
- bailoutHooks(current, workInProgress, renderExpirationTime);
- return bailoutOnAlreadyFinishedWork(
- current,
- workInProgress,
- renderExpirationTime,
- );
+ bailoutHooks(current, workInProgress, renderLanes);
+ return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);
}
// React DevTools reads this flag.
workInProgress.effectTag |= PerformedWork;
- reconcileChildren(
- current,
- workInProgress,
- nextChildren,
- renderExpirationTime,
- );
+ reconcileChildren(current, workInProgress, nextChildren, renderLanes);
return workInProgress.child;
}
@@ -816,7 +768,7 @@ function updateBlock(
workInProgress: Fiber,
block: BlockComponent,
nextProps: any,
- renderExpirationTime: ExpirationTimeOpaque,
+ renderLanes: Lanes,
) {
// TODO: current can be non-null here even if the component
// hasn't yet mounted. This happens after the first render suspends.
@@ -827,7 +779,7 @@ function updateBlock(
// The rest is a fork of updateFunctionComponent
let nextChildren;
- prepareToReadContext(workInProgress, renderExpirationTime);
+ prepareToReadContext(workInProgress, renderLanes);
if (__DEV__) {
ReactCurrentOwner.current = workInProgress;
setIsRendering(true);
@@ -837,7 +789,7 @@ function updateBlock(
render,
nextProps,
data,
- renderExpirationTime,
+ renderLanes,
);
if (
debugRenderPhaseSideEffectsForStrictMode &&
@@ -851,7 +803,7 @@ function updateBlock(
render,
nextProps,
data,
- renderExpirationTime,
+ renderLanes,
);
} finally {
reenableLogs();
@@ -865,27 +817,18 @@ function updateBlock(
render,
nextProps,
data,
- renderExpirationTime,
+ renderLanes,
);
}
if (current !== null && !didReceiveUpdate) {
- bailoutHooks(current, workInProgress, renderExpirationTime);
- return bailoutOnAlreadyFinishedWork(
- current,
- workInProgress,
- renderExpirationTime,
- );
+ bailoutHooks(current, workInProgress, renderLanes);
+ return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);
}
// React DevTools reads this flag.
workInProgress.effectTag |= PerformedWork;
- reconcileChildren(
- current,
- workInProgress,
- nextChildren,
- renderExpirationTime,
- );
+ reconcileChildren(current, workInProgress, nextChildren, renderLanes);
return workInProgress.child;
}
@@ -893,8 +836,8 @@ function updateClassComponent(
current: Fiber | null,
workInProgress: Fiber,
Component: any,
- nextProps,
- renderExpirationTime: ExpirationTimeOpaque,
+ nextProps: any,
+ renderLanes: Lanes,
) {
if (__DEV__) {
if (workInProgress.type !== workInProgress.elementType) {
@@ -922,7 +865,7 @@ function updateClassComponent(
} else {
hasContext = false;
}
- prepareToReadContext(workInProgress, renderExpirationTime);
+ prepareToReadContext(workInProgress, renderLanes);
const instance = workInProgress.stateNode;
let shouldUpdate;
@@ -939,12 +882,7 @@ function updateClassComponent(
}
// In the initial pass we might need to construct the instance.
constructClassInstance(workInProgress, Component, nextProps);
- mountClassInstance(
- workInProgress,
- Component,
- nextProps,
- renderExpirationTime,
- );
+ mountClassInstance(workInProgress, Component, nextProps, renderLanes);
shouldUpdate = true;
} else if (current === null) {
// In a resume, we'll already have an instance we can reuse.
@@ -952,7 +890,7 @@ function updateClassComponent(
workInProgress,
Component,
nextProps,
- renderExpirationTime,
+ renderLanes,
);
} else {
shouldUpdate = updateClassInstance(
@@ -960,7 +898,7 @@ function updateClassComponent(
workInProgress,
Component,
nextProps,
- renderExpirationTime,
+ renderLanes,
);
}
const nextUnitOfWork = finishClassComponent(
@@ -969,7 +907,7 @@ function updateClassComponent(
Component,
shouldUpdate,
hasContext,
- renderExpirationTime,
+ renderLanes,
);
if (__DEV__) {
const inst = workInProgress.stateNode;
@@ -993,7 +931,7 @@ function finishClassComponent(
Component: any,
shouldUpdate: boolean,
hasContext: boolean,
- renderExpirationTime: ExpirationTimeOpaque,
+ renderLanes: Lanes,
) {
// Refs should update even if shouldComponentUpdate returns false
markRef(current, workInProgress);
@@ -1006,11 +944,7 @@ function finishClassComponent(
invalidateContextProvider(workInProgress, Component, false);
}
- return bailoutOnAlreadyFinishedWork(
- current,
- workInProgress,
- renderExpirationTime,
- );
+ return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);
}
const instance = workInProgress.stateNode;
@@ -1064,15 +998,10 @@ function finishClassComponent(
current,
workInProgress,
nextChildren,
- renderExpirationTime,
+ renderLanes,
);
} else {
- reconcileChildren(
- current,
- workInProgress,
- nextChildren,
- renderExpirationTime,
- );
+ reconcileChildren(current, workInProgress, nextChildren, renderLanes);
}
// Memoize state using the values we just used to render.
@@ -1102,7 +1031,7 @@ function pushHostRootContext(workInProgress) {
pushHostContainer(workInProgress, root.containerInfo);
}
-function updateHostRoot(current, workInProgress, renderExpirationTime) {
+function updateHostRoot(current, workInProgress, renderLanes) {
pushHostRootContext(workInProgress);
const updateQueue = workInProgress.updateQueue;
invariant(
@@ -1115,20 +1044,14 @@ function updateHostRoot(current, workInProgress, renderExpirationTime) {
const prevState = workInProgress.memoizedState;
const prevChildren = prevState !== null ? prevState.element : null;
cloneUpdateQueue(current, workInProgress);
- processUpdateQueue(workInProgress, nextProps, null, renderExpirationTime);
+ processUpdateQueue(workInProgress, nextProps, null, renderLanes);
const nextState = workInProgress.memoizedState;
// Caution: React DevTools currently depends on this property
// being called "element".
const nextChildren = nextState.element;
if (nextChildren === prevChildren) {
- // If the state is the same as before, that's a bailout because we had
- // no work that expires at this time.
resetHydrationState();
- return bailoutOnAlreadyFinishedWork(
- current,
- workInProgress,
- renderExpirationTime,
- );
+ return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);
}
const root: FiberRoot = workInProgress.stateNode;
if (root.hydrate && enterHydrationState(workInProgress)) {
@@ -1141,7 +1064,7 @@ function updateHostRoot(current, workInProgress, renderExpirationTime) {
workInProgress,
null,
nextChildren,
- renderExpirationTime,
+ renderLanes,
);
workInProgress.child = child;
@@ -1159,12 +1082,7 @@ function updateHostRoot(current, workInProgress, renderExpirationTime) {
} else {
// Otherwise reset hydration state in case we aborted and resumed another
// root.
- reconcileChildren(
- current,
- workInProgress,
- nextChildren,
- renderExpirationTime,
- );
+ reconcileChildren(current, workInProgress, nextChildren, renderLanes);
resetHydrationState();
}
return workInProgress.child;
@@ -1173,7 +1091,7 @@ function updateHostRoot(current, workInProgress, renderExpirationTime) {
function updateHostComponent(
current: Fiber | null,
workInProgress: Fiber,
- renderExpirationTime: ExpirationTimeOpaque,
+ renderLanes: Lanes,
) {
pushHostContext(workInProgress);
@@ -1221,12 +1139,7 @@ function updateHostComponent(
nextChildren = wrappedChildren;
}
- reconcileChildren(
- current,
- workInProgress,
- nextChildren,
- renderExpirationTime,
- );
+ reconcileChildren(current, workInProgress, nextChildren, renderLanes);
return workInProgress.child;
}
@@ -1243,8 +1156,8 @@ function mountLazyComponent(
_current,
workInProgress,
elementType,
- updateExpirationTime,
- renderExpirationTime,
+ updateLanes,
+ renderLanes,
) {
if (_current !== null) {
// A lazy component only mounts if it suspended inside a non-
@@ -1280,7 +1193,7 @@ function mountLazyComponent(
workInProgress,
Component,
resolvedProps,
- renderExpirationTime,
+ renderLanes,
);
return child;
}
@@ -1295,7 +1208,7 @@ function mountLazyComponent(
workInProgress,
Component,
resolvedProps,
- renderExpirationTime,
+ renderLanes,
);
return child;
}
@@ -1310,7 +1223,7 @@ function mountLazyComponent(
workInProgress,
Component,
resolvedProps,
- renderExpirationTime,
+ renderLanes,
);
return child;
}
@@ -1333,8 +1246,8 @@ function mountLazyComponent(
workInProgress,
Component,
resolveDefaultProps(Component.type, resolvedProps), // The inner type can have defaults too
- updateExpirationTime,
- renderExpirationTime,
+ updateLanes,
+ renderLanes,
);
return child;
}
@@ -1346,7 +1259,7 @@ function mountLazyComponent(
workInProgress,
Component,
props,
- renderExpirationTime,
+ renderLanes,
);
return child;
}
@@ -1380,7 +1293,7 @@ function mountIncompleteClassComponent(
workInProgress,
Component,
nextProps,
- renderExpirationTime,
+ renderLanes,
) {
if (_current !== null) {
// An incomplete component only mounts if it suspended inside a non-
@@ -1408,15 +1321,10 @@ function mountIncompleteClassComponent(
} else {
hasContext = false;
}
- prepareToReadContext(workInProgress, renderExpirationTime);
+ prepareToReadContext(workInProgress, renderLanes);
constructClassInstance(workInProgress, Component, nextProps);
- mountClassInstance(
- workInProgress,
- Component,
- nextProps,
- renderExpirationTime,
- );
+ mountClassInstance(workInProgress, Component, nextProps, renderLanes);
return finishClassComponent(
null,
@@ -1424,7 +1332,7 @@ function mountIncompleteClassComponent(
Component,
true,
hasContext,
- renderExpirationTime,
+ renderLanes,
);
}
@@ -1432,7 +1340,7 @@ function mountIndeterminateComponent(
_current,
workInProgress,
Component,
- renderExpirationTime,
+ renderLanes,
) {
if (_current !== null) {
// An indeterminate component only mounts if it suspended inside a non-
@@ -1456,7 +1364,7 @@ function mountIndeterminateComponent(
context = getMaskedContext(workInProgress, unmaskedContext);
}
- prepareToReadContext(workInProgress, renderExpirationTime);
+ prepareToReadContext(workInProgress, renderLanes);
let value;
if (__DEV__) {
@@ -1489,7 +1397,7 @@ function mountIndeterminateComponent(
Component,
props,
context,
- renderExpirationTime,
+ renderLanes,
);
setIsRendering(false);
} else {
@@ -1499,7 +1407,7 @@ function mountIndeterminateComponent(
Component,
props,
context,
- renderExpirationTime,
+ renderLanes,
);
}
// React DevTools reads this flag.
@@ -1591,14 +1499,14 @@ function mountIndeterminateComponent(
}
adoptClassInstance(workInProgress, value);
- mountClassInstance(workInProgress, Component, props, renderExpirationTime);
+ mountClassInstance(workInProgress, Component, props, renderLanes);
return finishClassComponent(
null,
workInProgress,
Component,
true,
hasContext,
- renderExpirationTime,
+ renderLanes,
);
} else {
// Proceed under the assumption that this is a function component
@@ -1624,14 +1532,14 @@ function mountIndeterminateComponent(
Component,
props,
context,
- renderExpirationTime,
+ renderLanes,
);
} finally {
reenableLogs();
}
}
}
- reconcileChildren(null, workInProgress, value, renderExpirationTime);
+ reconcileChildren(null, workInProgress, value, renderLanes);
if (__DEV__) {
validateFunctionComponentInDev(workInProgress, Component);
}
@@ -1719,30 +1627,21 @@ function validateFunctionComponentInDev(workInProgress: Fiber, Component: any) {
const SUSPENDED_MARKER: SuspenseState = {
dehydrated: null,
- retryTime: NoWork,
+ retryLane: NoLane,
};
-function mountSuspenseOffscreenState(
- renderExpirationTime: ExpirationTimeOpaque,
-): OffscreenState {
+function mountSuspenseOffscreenState(renderLanes: Lanes): OffscreenState {
return {
- baseTime: renderExpirationTime,
+ baseLanes: renderLanes,
};
}
function updateSuspenseOffscreenState(
prevOffscreenState: OffscreenState,
- renderExpirationTime: ExpirationTimeOpaque,
+ renderLanes: Lanes,
): OffscreenState {
- const prevBaseTime = prevOffscreenState.baseTime;
return {
- // Choose whichever time is inclusive of the other one. This represents
- // the union of all the levels that suspended.
- baseTime:
- !isSameExpirationTime(prevBaseTime, (NoWork: ExpirationTimeOpaque)) &&
- !isSameOrHigherPriority(prevBaseTime, renderExpirationTime)
- ? prevBaseTime
- : renderExpirationTime,
+ baseLanes: combineLanes(prevOffscreenState.baseLanes, renderLanes),
};
}
@@ -1750,7 +1649,7 @@ function shouldRemainOnFallback(
suspenseContext: SuspenseContext,
current: null | Fiber,
workInProgress: Fiber,
- renderExpirationTime: ExpirationTimeOpaque,
+ renderLanes: Lanes,
) {
// If we're already showing a fallback, there are cases where we need to
// remain on that fallback regardless of whether the content has resolved.
@@ -1773,44 +1672,12 @@ function shouldRemainOnFallback(
);
}
-function getRemainingWorkInPrimaryTree(
- current: Fiber,
- workInProgress: Fiber,
- renderExpirationTime,
-) {
- const currentChildExpirationTime = current.childExpirationTime_opaque;
- if (
- !isSameOrHigherPriority(currentChildExpirationTime, renderExpirationTime)
- ) {
- // The highest priority remaining work is not part of this render. So the
- // remaining work has not changed.
- return currentChildExpirationTime;
- }
-
- if ((workInProgress.mode & BlockingMode) !== NoMode) {
- // The highest priority remaining work is part of this render. Since we only
- // keep track of the highest level, we don't know if there's a lower
- // priority level scheduled. As a compromise, we'll render at the lowest
- // known level in the entire tree, since that will include everything.
- // TODO: If expirationTime were a bitmask where each bit represents a
- // separate task thread, this would be: currentChildBits & ~renderBits
- const root = getWorkInProgressRoot();
- if (root !== null) {
- const lastPendingTime = root.lastPendingTime_opaque;
- if (!isSameOrHigherPriority(lastPendingTime, renderExpirationTime)) {
- return lastPendingTime;
- }
- }
- }
- // In legacy mode, there's no work left.
- return NoWork;
+function getRemainingWorkInPrimaryTree(current: Fiber, renderLanes) {
+ // TODO: Should not remove render lanes that were pinged during this render
+ return removeLanes(current.childLanes, renderLanes);
}
-function updateSuspenseComponent(
- current,
- workInProgress,
- renderExpirationTime,
-) {
+function updateSuspenseComponent(current, workInProgress, renderLanes) {
const nextProps = workInProgress.pendingProps;
// This is used by DevTools to force a boundary to suspend.
@@ -1831,7 +1698,7 @@ function updateSuspenseComponent(
suspenseContext,
current,
workInProgress,
- renderExpirationTime,
+ renderLanes,
)
) {
// Something in this boundary's subtree already suspended. Switch to
@@ -1903,7 +1770,7 @@ function updateSuspenseComponent(
return mountDehydratedSuspenseComponent(
workInProgress,
dehydrated,
- renderExpirationTime,
+ renderLanes,
);
}
}
@@ -1917,11 +1784,11 @@ function updateSuspenseComponent(
workInProgress,
nextPrimaryChildren,
nextFallbackChildren,
- renderExpirationTime,
+ renderLanes,
);
const primaryChildFragment: Fiber = (workInProgress.child: any);
primaryChildFragment.memoizedState = mountSuspenseOffscreenState(
- renderExpirationTime,
+ renderLanes,
);
workInProgress.memoizedState = SUSPENDED_MARKER;
return fallbackFragment;
@@ -1930,7 +1797,7 @@ function updateSuspenseComponent(
return mountSuspensePrimaryChildren(
workInProgress,
nextPrimaryChildren,
- renderExpirationTime,
+ renderLanes,
);
}
} else {
@@ -1952,7 +1819,7 @@ function updateSuspenseComponent(
workInProgress,
dehydrated,
prevState,
- renderExpirationTime,
+ renderLanes,
);
} else if (
(workInProgress.memoizedState: null | SuspenseState) !== null
@@ -1974,11 +1841,11 @@ function updateSuspenseComponent(
workInProgress,
nextPrimaryChildren,
nextFallbackChildren,
- renderExpirationTime,
+ renderLanes,
);
const primaryChildFragment: Fiber = (workInProgress.child: any);
primaryChildFragment.memoizedState = mountSuspenseOffscreenState(
- renderExpirationTime,
+ renderLanes,
);
workInProgress.memoizedState = SUSPENDED_MARKER;
return fallbackChildFragment;
@@ -1994,22 +1861,18 @@ function updateSuspenseComponent(
workInProgress,
nextPrimaryChildren,
nextFallbackChildren,
- renderExpirationTime,
+ renderLanes,
);
const primaryChildFragment: Fiber = (workInProgress.child: any);
const prevOffscreenState: OffscreenState | null = (current.child: any)
.memoizedState;
primaryChildFragment.memoizedState =
prevOffscreenState === null
- ? mountSuspenseOffscreenState(renderExpirationTime)
- : updateSuspenseOffscreenState(
- prevOffscreenState,
- renderExpirationTime,
- );
- primaryChildFragment.childExpirationTime_opaque = getRemainingWorkInPrimaryTree(
+ ? mountSuspenseOffscreenState(renderLanes)
+ : updateSuspenseOffscreenState(prevOffscreenState, renderLanes);
+ primaryChildFragment.childLanes = getRemainingWorkInPrimaryTree(
current,
- workInProgress,
- renderExpirationTime,
+ renderLanes,
);
workInProgress.memoizedState = SUSPENDED_MARKER;
return fallbackChildFragment;
@@ -2019,7 +1882,7 @@ function updateSuspenseComponent(
current,
workInProgress,
nextPrimaryChildren,
- renderExpirationTime,
+ renderLanes,
);
workInProgress.memoizedState = null;
return primaryChildFragment;
@@ -2035,22 +1898,18 @@ function updateSuspenseComponent(
workInProgress,
nextPrimaryChildren,
nextFallbackChildren,
- renderExpirationTime,
+ renderLanes,
);
const primaryChildFragment: Fiber = (workInProgress.child: any);
const prevOffscreenState: OffscreenState | null = (current.child: any)
.memoizedState;
primaryChildFragment.memoizedState =
prevOffscreenState === null
- ? mountSuspenseOffscreenState(renderExpirationTime)
- : updateSuspenseOffscreenState(
- prevOffscreenState,
- renderExpirationTime,
- );
- primaryChildFragment.childExpirationTime_opaque = getRemainingWorkInPrimaryTree(
+ ? mountSuspenseOffscreenState(renderLanes)
+ : updateSuspenseOffscreenState(prevOffscreenState, renderLanes);
+ primaryChildFragment.childLanes = getRemainingWorkInPrimaryTree(
current,
- workInProgress,
- renderExpirationTime,
+ renderLanes,
);
// Skip the primary children, and continue working on the
// fallback children.
@@ -2064,7 +1923,7 @@ function updateSuspenseComponent(
current,
workInProgress,
nextPrimaryChildren,
- renderExpirationTime,
+ renderLanes,
);
workInProgress.memoizedState = null;
return primaryChildFragment;
@@ -2076,7 +1935,7 @@ function updateSuspenseComponent(
function mountSuspensePrimaryChildren(
workInProgress,
primaryChildren,
- renderExpirationTime,
+ renderLanes,
) {
const mode = workInProgress.mode;
const primaryChildProps: OffscreenProps = {
@@ -2086,7 +1945,7 @@ function mountSuspensePrimaryChildren(
const primaryChildFragment = createFiberFromOffscreen(
primaryChildProps,
mode,
- renderExpirationTime,
+ renderLanes,
null,
);
primaryChildFragment.return = workInProgress;
@@ -2098,7 +1957,7 @@ function mountSuspenseFallbackChildren(
workInProgress,
primaryChildren,
fallbackChildren,
- renderExpirationTime,
+ renderLanes,
) {
const mode = workInProgress.mode;
const progressedPrimaryFragment: Fiber | null = workInProgress.child;
@@ -2114,7 +1973,7 @@ function mountSuspenseFallbackChildren(
// In legacy mode, we commit the primary tree as if it successfully
// completed, even though it's in an inconsistent state.
primaryChildFragment = progressedPrimaryFragment;
- primaryChildFragment.childExpirationTime_opaque = NoWork;
+ primaryChildFragment.childLanes = NoLanes;
primaryChildFragment.pendingProps = primaryChildProps;
if (enableProfilerTimer && workInProgress.mode & ProfileMode) {
@@ -2131,20 +1990,20 @@ function mountSuspenseFallbackChildren(
fallbackChildFragment = createFiberFromFragment(
fallbackChildren,
mode,
- renderExpirationTime,
+ renderLanes,
null,
);
} else {
primaryChildFragment = createFiberFromOffscreen(
primaryChildProps,
mode,
- NoWork,
+ NoLanes,
null,
);
fallbackChildFragment = createFiberFromFragment(
fallbackChildren,
mode,
- renderExpirationTime,
+ renderLanes,
null,
);
}
@@ -2169,7 +2028,7 @@ function updateSuspensePrimaryChildren(
current,
workInProgress,
primaryChildren,
- renderExpirationTime,
+ renderLanes,
) {
const currentPrimaryChildFragment: Fiber = (current.child: any);
const currentFallbackChildFragment: Fiber | null =
@@ -2183,7 +2042,7 @@ function updateSuspensePrimaryChildren(
},
);
if ((workInProgress.mode & BlockingMode) === NoMode) {
- primaryChildFragment.expirationTime_opaque = renderExpirationTime;
+ primaryChildFragment.lanes = renderLanes;
}
primaryChildFragment.return = workInProgress;
primaryChildFragment.sibling = null;
@@ -2203,7 +2062,7 @@ function updateSuspenseFallbackChildren(
workInProgress,
primaryChildren,
fallbackChildren,
- renderExpirationTime,
+ renderLanes,
) {
const mode = workInProgress.mode;
const currentPrimaryChildFragment: Fiber = (current.child: any);
@@ -2221,7 +2080,7 @@ function updateSuspenseFallbackChildren(
// completed, even though it's in an inconsistent state.
const progressedPrimaryFragment: Fiber = (workInProgress.child: any);
primaryChildFragment = progressedPrimaryFragment;
- primaryChildFragment.childExpirationTime_opaque = NoWork;
+ primaryChildFragment.childLanes = NoLanes;
primaryChildFragment.pendingProps = primaryChildProps;
if (enableProfilerTimer && workInProgress.mode & ProfileMode) {
@@ -2268,7 +2127,7 @@ function updateSuspenseFallbackChildren(
fallbackChildFragment = createFiberFromFragment(
fallbackChildren,
mode,
- renderExpirationTime,
+ renderLanes,
null,
);
// Needs a placement effect because the parent (the Suspense boundary) already
@@ -2287,15 +2146,10 @@ function updateSuspenseFallbackChildren(
function retrySuspenseComponentWithoutHydrating(
current: Fiber,
workInProgress: Fiber,
- renderExpirationTime: ExpirationTimeOpaque,
+ renderLanes: Lanes,
) {
// This will add the old fiber to the deletion list
- reconcileChildFibers(
- workInProgress,
- current.child,
- null,
- renderExpirationTime,
- );
+ reconcileChildFibers(workInProgress, current.child, null, renderLanes);
// We're now not suspended nor dehydrated.
const nextProps = workInProgress.pendingProps;
@@ -2303,7 +2157,7 @@ function retrySuspenseComponentWithoutHydrating(
const primaryChildFragment = mountSuspensePrimaryChildren(
workInProgress,
primaryChildren,
- renderExpirationTime,
+ renderLanes,
);
// Needs a placement effect because the parent (the Suspense boundary) already
// mounted but this is a new fiber.
@@ -2318,19 +2172,19 @@ function mountSuspenseFallbackAfterRetryWithoutHydrating(
workInProgress,
primaryChildren,
fallbackChildren,
- renderExpirationTime,
+ renderLanes,
) {
const mode = workInProgress.mode;
const primaryChildFragment = createFiberFromOffscreen(
primaryChildren,
mode,
- NoWork,
+ NoLanes,
null,
);
const fallbackChildFragment = createFiberFromFragment(
fallbackChildren,
mode,
- renderExpirationTime,
+ renderLanes,
null,
);
// Needs a placement effect because the parent (the Suspense
@@ -2345,12 +2199,7 @@ function mountSuspenseFallbackAfterRetryWithoutHydrating(
if ((workInProgress.mode & BlockingMode) !== NoMode) {
// We will have dropped the effect list which contains the
// deletion. We need to reconcile to delete the current child.
- reconcileChildFibers(
- workInProgress,
- current.child,
- null,
- renderExpirationTime,
- );
+ reconcileChildFibers(workInProgress, current.child, null, renderLanes);
}
return fallbackChildFragment;
@@ -2359,7 +2208,7 @@ function mountSuspenseFallbackAfterRetryWithoutHydrating(
function mountDehydratedSuspenseComponent(
workInProgress: Fiber,
suspenseInstance: SuspenseInstance,
- renderExpirationTime: ExpirationTimeOpaque,
+ renderLanes: Lanes,
): null | Fiber {
// During the first pass, we'll bail out and not drill into the children.
// Instead, we'll leave the content in place and try to hydrate it later.
@@ -2373,7 +2222,7 @@ function mountDehydratedSuspenseComponent(
'the server rendered components.',
);
}
- workInProgress.expirationTime_opaque = Sync;
+ workInProgress.lanes = laneToLanes(SyncLane);
} else if (isSuspenseInstanceFallback(suspenseInstance)) {
// This is a client-only boundary. Since we won't get any content from the server
// for this, we need to schedule that at a higher priority based on when it would
@@ -2387,17 +2236,16 @@ function mountDehydratedSuspenseComponent(
// time. This will mean that Suspense timeouts are slightly shifted to later than
// they should be.
// Schedule a normal pri update to render this content.
- const newExpirationTime = DefaultUpdateTime;
if (enableSchedulerTracing) {
- markSpawnedWork(newExpirationTime);
+ markSpawnedWork(DefaultHydrationLane);
}
- workInProgress.expirationTime_opaque = newExpirationTime;
+ workInProgress.lanes = laneToLanes(DefaultHydrationLane);
} else {
// We'll continue hydrating the rest at offscreen priority since we'll already
// be showing the right content coming from the server, it is no rush.
- workInProgress.expirationTime_opaque = Never;
+ workInProgress.lanes = laneToLanes(OffscreenLane);
if (enableSchedulerTracing) {
- markSpawnedWork((Never: ExpirationTimeOpaque));
+ markSpawnedWork(OffscreenLane);
}
}
return null;
@@ -2408,7 +2256,7 @@ function updateDehydratedSuspenseComponent(
workInProgress: Fiber,
suspenseInstance: SuspenseInstance,
suspenseState: SuspenseState,
- renderExpirationTime: ExpirationTimeOpaque,
+ renderLanes: Lanes,
): null | Fiber {
// We should never be hydrating at this point because it is the first pass,
// but after we've already committed once.
@@ -2418,7 +2266,7 @@ function updateDehydratedSuspenseComponent(
return retrySuspenseComponentWithoutHydrating(
current,
workInProgress,
- renderExpirationTime,
+ renderLanes,
);
}
@@ -2429,36 +2277,30 @@ function updateDehydratedSuspenseComponent(
return retrySuspenseComponentWithoutHydrating(
current,
workInProgress,
- renderExpirationTime,
+ renderLanes,
);
}
- // We use childExpirationTime to indicate that a child might depend on context, so if
+ // We use lanes to indicate that a child might depend on context, so if
// any context has changed, we need to treat is as if the input might have changed.
- const hasContextChanged = isSameOrHigherPriority(
- current.childExpirationTime_opaque,
- renderExpirationTime,
- );
+ const hasContextChanged = includesSomeLane(renderLanes, current.childLanes);
if (didReceiveUpdate || hasContextChanged) {
// This boundary has changed since the first render. This means that we are now unable to
- // hydrate it. We might still be able to hydrate it using an earlier expiration time, if
- // we are rendering at lower expiration than sync.
- if (
- !isSameOrHigherPriority(
- renderExpirationTime,
- (Sync: ExpirationTimeOpaque),
- )
- ) {
+ // hydrate it. We might still be able to hydrate it using a higher priority lane.
+ const root = getWorkInProgressRoot();
+ if (root !== null) {
+ const attemptHydrationAtLane = getBumpedLaneForHydration(
+ root,
+ renderLanes,
+ );
if (
- isSameOrHigherPriority(renderExpirationTime, suspenseState.retryTime)
+ attemptHydrationAtLane !== NoLane &&
+ attemptHydrationAtLane !== suspenseState.retryLane
) {
- // This render is even higher pri than we've seen before, let's try again
- // at even higher pri.
- const attemptHydrationAtExpirationTime = bumpPriorityHigher(
- renderExpirationTime,
- );
- suspenseState.retryTime = attemptHydrationAtExpirationTime;
- scheduleUpdateOnFiber(current, attemptHydrationAtExpirationTime);
- // TODO: Early abort this render.
+ // Intentionally mutating since this render will get interrupted. This
+ // is one of the very rare times where we mutate the current tree
+ // during the render phase.
+ suspenseState.retryLane = attemptHydrationAtLane;
+ scheduleUpdateOnFiber(current, attemptHydrationAtLane);
} else {
// We have already tried to ping at a higher priority than we're rendering with
// so if we got here, we must have failed to hydrate at those levels. We must
@@ -2468,6 +2310,7 @@ function updateDehydratedSuspenseComponent(
// an opportunity to hydrate before this pass commits.
}
}
+
// If we have scheduled higher pri work above, this will probably just abort the render
// since we now have higher priority work, but in case it doesn't, we need to prepare to
// render something, if we time out. Even if that requires us to delete everything and
@@ -2477,7 +2320,7 @@ function updateDehydratedSuspenseComponent(
return retrySuspenseComponentWithoutHydrating(
current,
workInProgress,
- renderExpirationTime,
+ renderLanes,
);
} else if (isSuspenseInstancePending(suspenseInstance)) {
// This component is still pending more data from the server, so we can't hydrate its
@@ -2509,7 +2352,7 @@ function updateDehydratedSuspenseComponent(
const primaryChildFragment = mountSuspensePrimaryChildren(
workInProgress,
primaryChildren,
- renderExpirationTime,
+ renderLanes,
);
// Mark the children as hydrating. This is a fast path to know whether this
// tree is part of a hydrating tree. This is used to determine if a child
@@ -2522,32 +2365,19 @@ function updateDehydratedSuspenseComponent(
}
}
-function scheduleWorkOnFiber(
- fiber: Fiber,
- renderExpirationTime: ExpirationTimeOpaque,
-) {
- if (
- !isSameOrHigherPriority(fiber.expirationTime_opaque, renderExpirationTime)
- ) {
- fiber.expirationTime_opaque = renderExpirationTime;
- }
+function scheduleWorkOnFiber(fiber: Fiber, renderLanes: Lanes) {
+ fiber.lanes = combineLanes(fiber.lanes, renderLanes);
const alternate = fiber.alternate;
- if (
- alternate !== null &&
- !isSameOrHigherPriority(
- alternate.expirationTime_opaque,
- renderExpirationTime,
- )
- ) {
- alternate.expirationTime_opaque = renderExpirationTime;
+ if (alternate !== null) {
+ alternate.lanes = combineLanes(alternate.lanes, renderLanes);
}
- scheduleWorkOnParentPath(fiber.return, renderExpirationTime);
+ scheduleWorkOnParentPath(fiber.return, renderLanes);
}
function propagateSuspenseContextChange(
workInProgress: Fiber,
firstChild: null | Fiber,
- renderExpirationTime: ExpirationTimeOpaque,
+ renderLanes: Lanes,
): void {
// Mark any Suspense boundaries with fallbacks as having work to do.
// If they were previously forced into fallbacks, they may now be able
@@ -2557,7 +2387,7 @@ function propagateSuspenseContextChange(
if (node.tag === SuspenseComponent) {
const state: SuspenseState | null = node.memoizedState;
if (state !== null) {
- scheduleWorkOnFiber(node, renderExpirationTime);
+ scheduleWorkOnFiber(node, renderLanes);
}
} else if (node.tag === SuspenseListComponent) {
// If the tail is hidden there might not be an Suspense boundaries
@@ -2565,7 +2395,7 @@ function propagateSuspenseContextChange(
// list itself.
// We don't have to traverse to the children of the list since
// the list will propagate the change when it rerenders.
- scheduleWorkOnFiber(node, renderExpirationTime);
+ scheduleWorkOnFiber(node, renderLanes);
} else if (node.child !== null) {
node.child.return = node;
node = node.child;
@@ -2797,7 +2627,7 @@ function initSuspenseListRenderState(
function updateSuspenseListComponent(
current: Fiber | null,
workInProgress: Fiber,
- renderExpirationTime: ExpirationTimeOpaque,
+ renderLanes: Lanes,
) {
const nextProps = workInProgress.pendingProps;
const revealOrder: SuspenseListRevealOrder = nextProps.revealOrder;
@@ -2808,7 +2638,7 @@ function updateSuspenseListComponent(
validateTailOptions(tailMode, revealOrder);
validateSuspenseListChildren(newChildren, revealOrder);
- reconcileChildren(current, workInProgress, newChildren, renderExpirationTime);
+ reconcileChildren(current, workInProgress, newChildren, renderLanes);
let suspenseContext: SuspenseContext = suspenseStackCursor.current;
@@ -2832,7 +2662,7 @@ function updateSuspenseListComponent(
propagateSuspenseContextChange(
workInProgress,
workInProgress.child,
- renderExpirationTime,
+ renderLanes,
);
}
suspenseContext = setDefaultShallowSuspenseContext(suspenseContext);
@@ -2925,7 +2755,7 @@ function updateSuspenseListComponent(
function updatePortalComponent(
current: Fiber | null,
workInProgress: Fiber,
- renderExpirationTime: ExpirationTimeOpaque,
+ renderLanes: Lanes,
) {
pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo);
const nextChildren = workInProgress.pendingProps;
@@ -2939,15 +2769,10 @@ function updatePortalComponent(
workInProgress,
null,
nextChildren,
- renderExpirationTime,
+ renderLanes,
);
} else {
- reconcileChildren(
- current,
- workInProgress,
- nextChildren,
- renderExpirationTime,
- );
+ reconcileChildren(current, workInProgress, nextChildren, renderLanes);
}
return workInProgress.child;
}
@@ -2955,7 +2780,7 @@ function updatePortalComponent(
function updateContextProvider(
current: Fiber | null,
workInProgress: Fiber,
- renderExpirationTime: ExpirationTimeOpaque,
+ renderLanes: Lanes,
) {
const providerType: ReactProviderType = workInProgress.type;
const context: ReactContext = providerType._context;
@@ -2987,23 +2812,18 @@ function updateContextProvider(
return bailoutOnAlreadyFinishedWork(
current,
workInProgress,
- renderExpirationTime,
+ renderLanes,
);
}
} else {
// The context value changed. Search for matching consumers and schedule
// them to update.
- propagateContextChange(
- workInProgress,
- context,
- changedBits,
- renderExpirationTime,
- );
+ propagateContextChange(workInProgress, context, changedBits, renderLanes);
}
}
const newChildren = newProps.children;
- reconcileChildren(current, workInProgress, newChildren, renderExpirationTime);
+ reconcileChildren(current, workInProgress, newChildren, renderLanes);
return workInProgress.child;
}
@@ -3012,7 +2832,7 @@ let hasWarnedAboutUsingContextAsConsumer = false;
function updateContextConsumer(
current: Fiber | null,
workInProgress: Fiber,
- renderExpirationTime: ExpirationTimeOpaque,
+ renderLanes: Lanes,
) {
let context: ReactContext = workInProgress.type;
// The logic below for Context differs depending on PROD or DEV mode. In
@@ -3054,7 +2874,7 @@ function updateContextConsumer(
}
}
- prepareToReadContext(workInProgress, renderExpirationTime);
+ prepareToReadContext(workInProgress, renderLanes);
const newValue = readContext(context, newProps.unstable_observedBits);
let newChildren;
if (__DEV__) {
@@ -3068,15 +2888,11 @@ function updateContextConsumer(
// React DevTools reads this flag.
workInProgress.effectTag |= PerformedWork;
- reconcileChildren(current, workInProgress, newChildren, renderExpirationTime);
+ reconcileChildren(current, workInProgress, newChildren, renderLanes);
return workInProgress.child;
}
-function updateFundamentalComponent(
- current,
- workInProgress,
- renderExpirationTime,
-) {
+function updateFundamentalComponent(current, workInProgress, renderLanes) {
const fundamentalImpl = workInProgress.type.impl;
if (fundamentalImpl.reconcileChildren === false) {
return null;
@@ -3084,25 +2900,15 @@ function updateFundamentalComponent(
const nextProps = workInProgress.pendingProps;
const nextChildren = nextProps.children;
- reconcileChildren(
- current,
- workInProgress,
- nextChildren,
- renderExpirationTime,
- );
+ reconcileChildren(current, workInProgress, nextChildren, renderLanes);
return workInProgress.child;
}
-function updateScopeComponent(current, workInProgress, renderExpirationTime) {
+function updateScopeComponent(current, workInProgress, renderLanes) {
const nextProps = workInProgress.pendingProps;
const nextChildren = nextProps.children;
- reconcileChildren(
- current,
- workInProgress,
- nextChildren,
- renderExpirationTime,
- );
+ reconcileChildren(current, workInProgress, nextChildren, renderLanes);
return workInProgress.child;
}
@@ -3113,7 +2919,7 @@ export function markWorkInProgressReceivedUpdate() {
function bailoutOnAlreadyFinishedWork(
current: Fiber | null,
workInProgress: Fiber,
- renderExpirationTime: ExpirationTimeOpaque,
+ renderLanes: Lanes,
): Fiber | null {
if (current !== null) {
// Reuse previous dependencies
@@ -3125,16 +2931,10 @@ function bailoutOnAlreadyFinishedWork(
stopProfilerTimerIfRunning(workInProgress);
}
- const updateExpirationTime = workInProgress.expirationTime_opaque;
- if (
- !isSameExpirationTime(updateExpirationTime, (NoWork: ExpirationTimeOpaque))
- ) {
- markUnprocessedUpdateTime(updateExpirationTime);
- }
+ markSkippedUpdateLanes(workInProgress.lanes);
// Check if the children have any pending work.
- const childExpirationTime = workInProgress.childExpirationTime_opaque;
- if (!isSameOrHigherPriority(childExpirationTime, renderExpirationTime)) {
+ if (!includesSomeLane(renderLanes, workInProgress.childLanes)) {
// The children don't have any work either. We can skip them.
// TODO: Once we add back resuming, we should check if the children are
// a work-in-progress set. If so, we need to transfer their effects.
@@ -3213,9 +3013,9 @@ function remountFiber(
function beginWork(
current: Fiber | null,
workInProgress: Fiber,
- renderExpirationTime: ExpirationTimeOpaque,
+ renderLanes: Lanes,
): Fiber | null {
- const updateExpirationTime = workInProgress.expirationTime_opaque;
+ const updateLanes = workInProgress.lanes;
if (__DEV__) {
if (workInProgress._debugNeedsRemount && current !== null) {
@@ -3229,7 +3029,7 @@ function beginWork(
workInProgress.pendingProps,
workInProgress._debugOwner || null,
workInProgress.mode,
- workInProgress.expirationTime_opaque,
+ workInProgress.lanes,
),
);
}
@@ -3248,9 +3048,7 @@ function beginWork(
// If props or context changed, mark the fiber as having performed work.
// This may be unset if the props are determined to be equal later (memo).
didReceiveUpdate = true;
- } else if (
- !isSameOrHigherPriority(updateExpirationTime, renderExpirationTime)
- ) {
+ } else if (!includesSomeLane(renderLanes, updateLanes)) {
didReceiveUpdate = false;
// This fiber does not have any pending work. Bailout without entering
// the begin phase. There's still some bookkeeping we that needs to be done
@@ -3284,9 +3082,9 @@ function beginWork(
case Profiler:
if (enableProfilerTimer) {
// Profiler should only call onRender when one of its descendants actually rendered.
- const hasChildWork = isSameOrHigherPriority(
- workInProgress.childExpirationTime_opaque,
- renderExpirationTime,
+ const hasChildWork = includesSomeLane(
+ renderLanes,
+ workInProgress.childLanes,
);
if (hasChildWork) {
workInProgress.effectTag |= Update;
@@ -3321,20 +3119,14 @@ function beginWork(
// go straight to the fallback. Check the priority of the primary
// child fragment.
const primaryChildFragment: Fiber = (workInProgress.child: any);
- const primaryChildExpirationTime =
- primaryChildFragment.childExpirationTime_opaque;
- if (
- isSameOrHigherPriority(
- primaryChildExpirationTime,
- renderExpirationTime,
- )
- ) {
+ const primaryChildLanes = primaryChildFragment.childLanes;
+ if (includesSomeLane(renderLanes, primaryChildLanes)) {
// The primary children have pending work. Use the normal path
// to attempt to render the primary children again.
return updateSuspenseComponent(
current,
workInProgress,
- renderExpirationTime,
+ renderLanes,
);
} else {
// The primary child fragment does not have pending work marked
@@ -3348,7 +3140,7 @@ function beginWork(
const child = bailoutOnAlreadyFinishedWork(
current,
workInProgress,
- renderExpirationTime,
+ renderLanes,
);
if (child !== null) {
// The fallback children have pending work. Skip over the
@@ -3370,9 +3162,9 @@ function beginWork(
const didSuspendBefore =
(current.effectTag & DidCapture) !== NoEffect;
- const hasChildWork = isSameOrHigherPriority(
- workInProgress.childExpirationTime_opaque,
- renderExpirationTime,
+ const hasChildWork = includesSomeLane(
+ renderLanes,
+ workInProgress.childLanes,
);
if (didSuspendBefore) {
@@ -3385,7 +3177,7 @@ function beginWork(
return updateSuspenseListComponent(
current,
workInProgress,
- renderExpirationTime,
+ renderLanes,
);
}
// If none of the children had any work, that means that none of
@@ -3426,19 +3218,11 @@ function beginWork(
// TODO: Probably should refactor `beginWork` to split the bailout
// path from the normal path. I'm tempted to do a labeled break here
// but I won't :)
- workInProgress.expirationTime_opaque = NoWork;
- return updateOffscreenComponent(
- current,
- workInProgress,
- renderExpirationTime,
- );
+ workInProgress.lanes = NoLanes;
+ return updateOffscreenComponent(current, workInProgress, renderLanes);
}
}
- return bailoutOnAlreadyFinishedWork(
- current,
- workInProgress,
- renderExpirationTime,
- );
+ return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);
} else {
// An update was scheduled on this fiber, but there are no new props
// nor legacy context. Set this to false. If an update queue or context
@@ -3451,11 +3235,7 @@ function beginWork(
}
// Before entering the begin phase, clear pending update priority.
- // TODO: This assumes that we're about to evaluate the component and process
- // the update queue. However, there's an exception: SimpleMemoComponent
- // sometimes bails out later in the begin phase. This indicates that we should
- // move this assignment out of the common path and into each branch.
- workInProgress.expirationTime_opaque = NoWork;
+ workInProgress.lanes = NoLanes;
switch (workInProgress.tag) {
case IndeterminateComponent: {
@@ -3463,7 +3243,7 @@ function beginWork(
current,
workInProgress,
workInProgress.type,
- renderExpirationTime,
+ renderLanes,
);
}
case LazyComponent: {
@@ -3472,8 +3252,8 @@ function beginWork(
current,
workInProgress,
elementType,
- updateExpirationTime,
- renderExpirationTime,
+ updateLanes,
+ renderLanes,
);
}
case FunctionComponent: {
@@ -3488,7 +3268,7 @@ function beginWork(
workInProgress,
Component,
resolvedProps,
- renderExpirationTime,
+ renderLanes,
);
}
case ClassComponent: {
@@ -3503,27 +3283,19 @@ function beginWork(
workInProgress,
Component,
resolvedProps,
- renderExpirationTime,
+ renderLanes,
);
}
case HostRoot:
- return updateHostRoot(current, workInProgress, renderExpirationTime);
+ return updateHostRoot(current, workInProgress, renderLanes);
case HostComponent:
- return updateHostComponent(current, workInProgress, renderExpirationTime);
+ return updateHostComponent(current, workInProgress, renderLanes);
case HostText:
return updateHostText(current, workInProgress);
case SuspenseComponent:
- return updateSuspenseComponent(
- current,
- workInProgress,
- renderExpirationTime,
- );
+ return updateSuspenseComponent(current, workInProgress, renderLanes);
case HostPortal:
- return updatePortalComponent(
- current,
- workInProgress,
- renderExpirationTime,
- );
+ return updatePortalComponent(current, workInProgress, renderLanes);
case ForwardRef: {
const type = workInProgress.type;
const unresolvedProps = workInProgress.pendingProps;
@@ -3536,27 +3308,19 @@ function beginWork(
workInProgress,
type,
resolvedProps,
- renderExpirationTime,
+ renderLanes,
);
}
case Fragment:
- return updateFragment(current, workInProgress, renderExpirationTime);
+ return updateFragment(current, workInProgress, renderLanes);
case Mode:
- return updateMode(current, workInProgress, renderExpirationTime);
+ return updateMode(current, workInProgress, renderLanes);
case Profiler:
- return updateProfiler(current, workInProgress, renderExpirationTime);
+ return updateProfiler(current, workInProgress, renderLanes);
case ContextProvider:
- return updateContextProvider(
- current,
- workInProgress,
- renderExpirationTime,
- );
+ return updateContextProvider(current, workInProgress, renderLanes);
case ContextConsumer:
- return updateContextConsumer(
- current,
- workInProgress,
- renderExpirationTime,
- );
+ return updateContextConsumer(current, workInProgress, renderLanes);
case MemoComponent: {
const type = workInProgress.type;
const unresolvedProps = workInProgress.pendingProps;
@@ -3581,8 +3345,8 @@ function beginWork(
workInProgress,
type,
resolvedProps,
- updateExpirationTime,
- renderExpirationTime,
+ updateLanes,
+ renderLanes,
);
}
case SimpleMemoComponent: {
@@ -3591,8 +3355,8 @@ function beginWork(
workInProgress,
workInProgress.type,
workInProgress.pendingProps,
- updateExpirationTime,
- renderExpirationTime,
+ updateLanes,
+ renderLanes,
);
}
case IncompleteClassComponent: {
@@ -3607,33 +3371,21 @@ function beginWork(
workInProgress,
Component,
resolvedProps,
- renderExpirationTime,
+ renderLanes,
);
}
case SuspenseListComponent: {
- return updateSuspenseListComponent(
- current,
- workInProgress,
- renderExpirationTime,
- );
+ return updateSuspenseListComponent(current, workInProgress, renderLanes);
}
case FundamentalComponent: {
if (enableFundamentalAPI) {
- return updateFundamentalComponent(
- current,
- workInProgress,
- renderExpirationTime,
- );
+ return updateFundamentalComponent(current, workInProgress, renderLanes);
}
break;
}
case ScopeComponent: {
if (enableScopeAPI) {
- return updateScopeComponent(
- current,
- workInProgress,
- renderExpirationTime,
- );
+ return updateScopeComponent(current, workInProgress, renderLanes);
}
break;
}
@@ -3641,29 +3393,15 @@ function beginWork(
if (enableBlocksAPI) {
const block = workInProgress.type;
const props = workInProgress.pendingProps;
- return updateBlock(
- current,
- workInProgress,
- block,
- props,
- renderExpirationTime,
- );
+ return updateBlock(current, workInProgress, block, props, renderLanes);
}
break;
}
case OffscreenComponent: {
- return updateOffscreenComponent(
- current,
- workInProgress,
- renderExpirationTime,
- );
+ return updateOffscreenComponent(current, workInProgress, renderLanes);
}
case LegacyHiddenComponent: {
- return updateLegacyHiddenComponent(
- current,
- workInProgress,
- renderExpirationTime,
- );
+ return updateLegacyHiddenComponent(current, workInProgress, renderLanes);
}
}
invariant(
diff --git a/packages/react-reconciler/src/ReactFiberClassComponent.new.js b/packages/react-reconciler/src/ReactFiberClassComponent.new.js
index b568278d452be..20e544b00a056 100644
--- a/packages/react-reconciler/src/ReactFiberClassComponent.new.js
+++ b/packages/react-reconciler/src/ReactFiberClassComponent.new.js
@@ -8,7 +8,7 @@
*/
import type {Fiber} from './ReactInternalTypes';
-import type {ExpirationTimeOpaque} from './ReactFiberExpirationTime.new';
+import type {Lanes} from './ReactFiberLane';
import type {UpdateQueue} from './ReactUpdateQueue.new';
import * as React from 'react';
@@ -40,7 +40,7 @@ import {
initializeUpdateQueue,
cloneUpdateQueue,
} from './ReactUpdateQueue.new';
-import {NoWork, isSameExpirationTime} from './ReactFiberExpirationTime.new';
+import {NoLanes} from './ReactFiberLane';
import {
cacheContext,
getMaskedContext,
@@ -51,7 +51,7 @@ import {
import {readContext} from './ReactFiberNewContext.new';
import {
requestEventTime,
- requestUpdateExpirationTime,
+ requestUpdateLane,
scheduleUpdateOnFiber,
} from './ReactFiberWorkLoop.new';
import {requestCurrentSuspenseConfig} from './ReactFiberSuspenseConfig';
@@ -177,12 +177,7 @@ export function applyDerivedStateFromProps(
// Once the update queue is empty, persist the derived state onto the
// base state.
- if (
- isSameExpirationTime(
- workInProgress.expirationTime_opaque,
- (NoWork: ExpirationTimeOpaque),
- )
- ) {
+ if (workInProgress.lanes === NoLanes) {
// Queue is always non-null for classes
const updateQueue: UpdateQueue = (workInProgress.updateQueue: any);
updateQueue.baseState = memoizedState;
@@ -195,9 +190,9 @@ const classComponentUpdater = {
const fiber = getInstance(inst);
const eventTime = requestEventTime();
const suspenseConfig = requestCurrentSuspenseConfig();
- const expirationTime = requestUpdateExpirationTime(fiber, suspenseConfig);
+ const lane = requestUpdateLane(fiber, suspenseConfig);
- const update = createUpdate(eventTime, expirationTime, suspenseConfig);
+ const update = createUpdate(eventTime, lane, suspenseConfig);
update.payload = payload;
if (callback !== undefined && callback !== null) {
if (__DEV__) {
@@ -207,15 +202,15 @@ const classComponentUpdater = {
}
enqueueUpdate(fiber, update);
- scheduleUpdateOnFiber(fiber, expirationTime);
+ scheduleUpdateOnFiber(fiber, lane);
},
enqueueReplaceState(inst, payload, callback) {
const fiber = getInstance(inst);
const eventTime = requestEventTime();
const suspenseConfig = requestCurrentSuspenseConfig();
- const expirationTime = requestUpdateExpirationTime(fiber, suspenseConfig);
+ const lane = requestUpdateLane(fiber, suspenseConfig);
- const update = createUpdate(eventTime, expirationTime, suspenseConfig);
+ const update = createUpdate(eventTime, lane, suspenseConfig);
update.tag = ReplaceState;
update.payload = payload;
@@ -227,15 +222,15 @@ const classComponentUpdater = {
}
enqueueUpdate(fiber, update);
- scheduleUpdateOnFiber(fiber, expirationTime);
+ scheduleUpdateOnFiber(fiber, lane);
},
enqueueForceUpdate(inst, callback) {
const fiber = getInstance(inst);
const eventTime = requestEventTime();
const suspenseConfig = requestCurrentSuspenseConfig();
- const expirationTime = requestUpdateExpirationTime(fiber, suspenseConfig);
+ const lane = requestUpdateLane(fiber, suspenseConfig);
- const update = createUpdate(eventTime, expirationTime, suspenseConfig);
+ const update = createUpdate(eventTime, lane, suspenseConfig);
update.tag = ForceUpdate;
if (callback !== undefined && callback !== null) {
@@ -246,7 +241,7 @@ const classComponentUpdater = {
}
enqueueUpdate(fiber, update);
- scheduleUpdateOnFiber(fiber, expirationTime);
+ scheduleUpdateOnFiber(fiber, lane);
},
};
@@ -771,7 +766,7 @@ function mountClassInstance(
workInProgress: Fiber,
ctor: any,
newProps: any,
- renderExpirationTime: ExpirationTimeOpaque,
+ renderLanes: Lanes,
): void {
if (__DEV__) {
checkClassInstance(workInProgress, ctor, newProps);
@@ -823,7 +818,7 @@ function mountClassInstance(
}
}
- processUpdateQueue(workInProgress, newProps, instance, renderExpirationTime);
+ processUpdateQueue(workInProgress, newProps, instance, renderLanes);
instance.state = workInProgress.memoizedState;
const getDerivedStateFromProps = ctor.getDerivedStateFromProps;
@@ -848,12 +843,7 @@ function mountClassInstance(
callComponentWillMount(workInProgress, instance);
// If we had additional state updates during this life-cycle, let's
// process them now.
- processUpdateQueue(
- workInProgress,
- newProps,
- instance,
- renderExpirationTime,
- );
+ processUpdateQueue(workInProgress, newProps, instance, renderLanes);
instance.state = workInProgress.memoizedState;
}
@@ -866,7 +856,7 @@ function resumeMountClassInstance(
workInProgress: Fiber,
ctor: any,
newProps: any,
- renderExpirationTime: ExpirationTimeOpaque,
+ renderLanes: Lanes,
): boolean {
const instance = workInProgress.stateNode;
@@ -917,7 +907,7 @@ function resumeMountClassInstance(
const oldState = workInProgress.memoizedState;
let newState = (instance.state = oldState);
- processUpdateQueue(workInProgress, newProps, instance, renderExpirationTime);
+ processUpdateQueue(workInProgress, newProps, instance, renderLanes);
newState = workInProgress.memoizedState;
if (
oldProps === newProps &&
@@ -1001,7 +991,7 @@ function updateClassInstance(
workInProgress: Fiber,
ctor: any,
newProps: any,
- renderExpirationTime: ExpirationTimeOpaque,
+ renderLanes: Lanes,
): boolean {
const instance = workInProgress.stateNode;
@@ -1058,7 +1048,7 @@ function updateClassInstance(
const oldState = workInProgress.memoizedState;
let newState = (instance.state = oldState);
- processUpdateQueue(workInProgress, newProps, instance, renderExpirationTime);
+ processUpdateQueue(workInProgress, newProps, instance, renderLanes);
newState = workInProgress.memoizedState;
if (
diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.new.js b/packages/react-reconciler/src/ReactFiberCommitWork.new.js
index 8e71d3a99bef6..91e74031dded8 100644
--- a/packages/react-reconciler/src/ReactFiberCommitWork.new.js
+++ b/packages/react-reconciler/src/ReactFiberCommitWork.new.js
@@ -17,7 +17,7 @@ import type {
} from './ReactFiberHostConfig';
import type {Fiber} from './ReactInternalTypes';
import type {FiberRoot} from './ReactInternalTypes';
-import type {ExpirationTimeOpaque} from './ReactFiberExpirationTime.new';
+import type {Lanes} from './ReactFiberLane';
import type {SuspenseState} from './ReactFiberSuspenseComponent.new';
import type {UpdateQueue} from './ReactUpdateQueue.new';
import type {FunctionComponentUpdateQueue} from './ReactFiberHooks.new';
@@ -516,7 +516,7 @@ function commitLifeCycles(
finishedRoot: FiberRoot,
current: Fiber | null,
finishedWork: Fiber,
- committedExpirationTime: ExpirationTimeOpaque,
+ committedLanes: Lanes,
): void {
switch (finishedWork.tag) {
case FunctionComponent:
diff --git a/packages/react-reconciler/src/ReactFiberCompleteWork.new.js b/packages/react-reconciler/src/ReactFiberCompleteWork.new.js
index e2280673232ba..e420bb6916c70 100644
--- a/packages/react-reconciler/src/ReactFiberCompleteWork.new.js
+++ b/packages/react-reconciler/src/ReactFiberCompleteWork.new.js
@@ -8,7 +8,7 @@
*/
import type {Fiber} from './ReactInternalTypes';
-import type {ExpirationTimeOpaque} from './ReactFiberExpirationTime.new';
+import type {Lanes} from './ReactFiberLane';
import type {
ReactFundamentalComponentInstance,
ReactScopeInstance,
@@ -133,10 +133,10 @@ import {
renderDidSuspend,
renderDidSuspendDelayIfPossible,
renderHasNotSuspendedYet,
- popRenderExpirationTime,
+ popRenderLanes,
} from './ReactFiberWorkLoop.new';
import {createFundamentalStateInstance} from './ReactFiberFundamental.new';
-import {Never, isSameOrHigherPriority} from './ReactFiberExpirationTime.new';
+import {OffscreenLane} from './ReactFiberLane';
import {resetChildFibers} from './ReactChildFiber.new';
import {updateDeprecatedEventListeners} from './ReactFiberDeprecatedEvents.new';
import {createScopeInstance} from './ReactFiberScope.new';
@@ -644,7 +644,7 @@ function cutOffTailIfNeeded(
function completeWork(
current: Fiber | null,
workInProgress: Fiber,
- renderExpirationTime: ExpirationTimeOpaque,
+ renderLanes: Lanes,
): Fiber | null {
const newProps = workInProgress.pendingProps;
@@ -857,7 +857,7 @@ function completeWork(
);
prepareToHydrateHostSuspenseInstance(workInProgress);
if (enableSchedulerTracing) {
- markSpawnedWork((Never: ExpirationTimeOpaque));
+ markSpawnedWork(OffscreenLane);
}
return null;
} else {
@@ -882,7 +882,7 @@ function completeWork(
if ((workInProgress.effectTag & DidCapture) !== NoEffect) {
// Something suspended. Re-render with the fallback children.
- workInProgress.expirationTime_opaque = renderExpirationTime;
+ workInProgress.lanes = renderLanes;
// Do not reset the effect list.
return workInProgress;
}
@@ -1051,7 +1051,7 @@ function completeWork(
}
workInProgress.lastEffect = renderState.lastEffect;
// Reset the child fibers to their original state.
- resetChildFibers(workInProgress, renderExpirationTime);
+ resetChildFibers(workInProgress, renderLanes);
// Set up the Suspense Context to force suspense and immediately
// rerender the children.
@@ -1111,10 +1111,7 @@ function completeWork(
// the expiration.
now() * 2 - renderState.renderingStartTime >
renderState.tailExpiration &&
- !isSameOrHigherPriority(
- (Never: ExpirationTimeOpaque),
- renderExpirationTime,
- )
+ renderLanes !== OffscreenLane
) {
// We have now passed our CPU deadline and we'll just give up further
// attempts to render the main content and only render fallbacks.
@@ -1129,9 +1126,9 @@ function completeWork(
// them, then they really have the same priority as this render.
// So we'll pick it back up the very next render pass once we've had
// an opportunity to yield for paint.
- workInProgress.expirationTime_opaque = renderExpirationTime;
+ workInProgress.lanes = renderLanes;
if (enableSchedulerTracing) {
- markSpawnedWork(renderExpirationTime);
+ markSpawnedWork(renderLanes);
}
}
}
@@ -1297,7 +1294,7 @@ function completeWork(
break;
case OffscreenComponent:
case LegacyHiddenComponent: {
- popRenderExpirationTime(workInProgress);
+ popRenderLanes(workInProgress);
if (current !== null) {
const nextState: OffscreenState | null = workInProgress.memoizedState;
const prevState: OffscreenState | null = current.memoizedState;
diff --git a/packages/react-reconciler/src/ReactFiberDeprecatedEvents.new.js b/packages/react-reconciler/src/ReactFiberDeprecatedEvents.new.js
index f77179fdb105c..26e055718cf84 100644
--- a/packages/react-reconciler/src/ReactFiberDeprecatedEvents.new.js
+++ b/packages/react-reconciler/src/ReactFiberDeprecatedEvents.new.js
@@ -19,7 +19,7 @@ import {
DEPRECATED_mountResponderInstance,
DEPRECATED_unmountResponderInstance,
} from './ReactFiberHostConfig';
-import {NoWork} from './ReactFiberExpirationTime.new';
+import {NoLanes} from './ReactFiberLane';
import {REACT_RESPONDER_TYPE} from 'shared/ReactSymbols';
@@ -154,7 +154,7 @@ export function updateDeprecatedEventListeners(
if (listeners != null) {
if (dependencies === null) {
dependencies = fiber.dependencies_new = {
- expirationTime: NoWork,
+ lanes: NoLanes,
firstContext: null,
responders: new Map(),
};
diff --git a/packages/react-reconciler/src/ReactFiberExpirationTime.new.js b/packages/react-reconciler/src/ReactFiberExpirationTime.new.js
deleted file mode 100644
index d8d3cfd69d5ab..0000000000000
--- a/packages/react-reconciler/src/ReactFiberExpirationTime.new.js
+++ /dev/null
@@ -1,92 +0,0 @@
-/**
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @flow
- */
-
-import type {ReactPriorityLevel} from './ReactInternalTypes';
-
-import {MAX_SIGNED_31_BIT_INT} from './MaxInts';
-
-import {
- ImmediatePriority,
- UserBlockingPriority,
- NormalPriority,
- IdlePriority,
-} from './SchedulerWithReactIntegration.new';
-
-export opaque type ExpirationTimeOpaque = number;
-
-export const NoWork: ExpirationTimeOpaque = 0;
-// TODO: Think of a better name for Never. The key difference with Idle is that
-// Never work can be committed in an inconsistent state without tearing the UI.
-// The main example is offscreen content, like a hidden subtree. So one possible
-// name is Offscreen. However, it also includes dehydrated Suspense boundaries,
-// which are inconsistent in the sense that they haven't finished yet, but
-// aren't visibly inconsistent because the server rendered HTML matches what the
-// hydrated tree would look like.
-export const Never: ExpirationTimeOpaque = 1;
-// Idle is slightly higher priority than Never. It must completely finish in
-// order to be consistent.
-export const Idle: ExpirationTimeOpaque = 2;
-// Continuous Hydration is slightly higher than Idle and is used to increase
-// priority of hover targets.
-export const ContinuousHydration: ExpirationTimeOpaque = 3;
-export const LongTransition: ExpirationTimeOpaque = 49999;
-export const ShortTransition: ExpirationTimeOpaque = 99999;
-export const DefaultUpdateTime: ExpirationTimeOpaque = 1073741296;
-export const UserBlockingUpdateTime: ExpirationTimeOpaque = 1073741761;
-export const Sync: ExpirationTimeOpaque = MAX_SIGNED_31_BIT_INT;
-export const Batched: ExpirationTimeOpaque = Sync - 1;
-
-// Accounts for -1 trick to bump updates into a different batch
-const ADJUSTMENT_OFFSET = 5;
-
-export function inferPriorityFromExpirationTime(
- expirationTime: ExpirationTimeOpaque,
-): ReactPriorityLevel {
- if (expirationTime >= Batched - ADJUSTMENT_OFFSET) {
- return ImmediatePriority;
- }
- if (expirationTime >= UserBlockingUpdateTime - ADJUSTMENT_OFFSET) {
- return UserBlockingPriority;
- }
- if (expirationTime >= LongTransition - ADJUSTMENT_OFFSET) {
- return NormalPriority;
- }
-
- // TODO: Handle LowPriority. Maybe should give it NormalPriority since Idle is
- // very agressively deprioritized.
-
- // Assume anything lower has idle priority
- return IdlePriority;
-}
-
-export function isSameOrHigherPriority(
- a: ExpirationTimeOpaque,
- b: ExpirationTimeOpaque,
-) {
- return a >= b;
-}
-
-export function isSameExpirationTime(
- a: ExpirationTimeOpaque,
- b: ExpirationTimeOpaque,
-) {
- return a === b;
-}
-
-export function bumpPriorityHigher(
- a: ExpirationTimeOpaque,
-): ExpirationTimeOpaque {
- return a + 1;
-}
-
-export function bumpPriorityLower(
- a: ExpirationTimeOpaque,
-): ExpirationTimeOpaque {
- return a - 1;
-}
diff --git a/packages/react-reconciler/src/ReactFiberHooks.new.js b/packages/react-reconciler/src/ReactFiberHooks.new.js
index 818a7e529bff5..03c6d44e58d67 100644
--- a/packages/react-reconciler/src/ReactFiberHooks.new.js
+++ b/packages/react-reconciler/src/ReactFiberHooks.new.js
@@ -16,7 +16,7 @@ import type {
ReactEventResponderListener,
} from 'shared/ReactTypes';
import type {Fiber, Dispatcher} from './ReactInternalTypes';
-import type {ExpirationTimeOpaque} from './ReactFiberExpirationTime.new';
+import type {Lanes, Lane} from './ReactFiberLane';
import type {HookEffectTag} from './ReactHookEffectTags';
import type {SuspenseConfig} from './ReactFiberSuspenseConfig';
import type {ReactPriorityLevel} from './ReactInternalTypes';
@@ -25,14 +25,16 @@ import type {OpaqueIDType} from './ReactFiberHostConfig';
import ReactSharedInternals from 'shared/ReactSharedInternals';
-import {markRootExpiredAtTime} from './ReactFiberRoot.new';
-import {
- NoWork,
- Sync,
- isSameOrHigherPriority,
- isSameExpirationTime,
-} from './ReactFiberExpirationTime.new';
import {NoMode, BlockingMode} from './ReactTypeOfMode';
+import {
+ NoLane,
+ NoLanes,
+ isSubsetOfLanes,
+ combineLanes,
+ removeLanes,
+ markRootExpired,
+ markRootMutableRead,
+} from './ReactFiberLane';
import {readContext} from './ReactFiberNewContext.new';
import {createDeprecatedResponderListener} from './ReactFiberDeprecatedEvents.new';
import {
@@ -47,13 +49,13 @@ import {
import {
getWorkInProgressRoot,
scheduleUpdateOnFiber,
- requestUpdateExpirationTime,
+ requestUpdateLane,
requestEventTime,
warnIfNotCurrentlyActingEffectsInDEV,
warnIfNotCurrentlyActingUpdatesInDev,
warnIfNotScopedWithMatchingAct,
markRenderEventTimeAndConfig,
- markUnprocessedUpdateTime,
+ markSkippedUpdateLanes,
} from './ReactFiberWorkLoop.new';
import invariant from 'shared/invariant';
@@ -74,10 +76,8 @@ import {
makeOpaqueHydratingObject,
} from './ReactFiberHostConfig';
import {
- getLastPendingExpirationTime,
getWorkInProgressVersion,
markSourceAsDirty,
- setPendingExpirationTime,
setWorkInProgressVersion,
warnAboutMultipleRenderersDEV,
} from './ReactMutableSource.new';
@@ -89,7 +89,7 @@ type Update = {|
// TODO: Temporary field. Will remove this by storing a map of
// transition -> start time on the root.
eventTime: number,
- expirationTime: ExpirationTimeOpaque,
+ lane: Lane,
suspenseConfig: null | SuspenseConfig,
action: A,
eagerReducer: ((S, A) => S) | null,
@@ -156,7 +156,7 @@ type BasicStateAction = (S => S) | S;
type Dispatch = A => void;
// These are set right before calling the component.
-let renderExpirationTime: ExpirationTimeOpaque = NoWork;
+let renderLanes: Lanes = NoLanes;
// The work-in-progress fiber. I've named it differently to distinguish it from
// the work-in-progress hook.
let currentlyRenderingFiber: Fiber = (null: any);
@@ -347,9 +347,9 @@ export function renderWithHooks(
Component: (p: Props, arg: SecondArg) => any,
props: Props,
secondArg: SecondArg,
- nextRenderExpirationTime: ExpirationTimeOpaque,
+ nextRenderLanes: Lanes,
): any {
- renderExpirationTime = nextRenderExpirationTime;
+ renderLanes = nextRenderLanes;
currentlyRenderingFiber = workInProgress;
if (__DEV__) {
@@ -365,7 +365,7 @@ export function renderWithHooks(
workInProgress.memoizedState = null;
workInProgress.updateQueue = null;
- workInProgress.expirationTime_opaque = NoWork;
+ workInProgress.lanes = NoLanes;
// The following should have already been reset
// currentHook = null;
@@ -454,7 +454,7 @@ export function renderWithHooks(
const didRenderTooFewHooks =
currentHook !== null && currentHook.next !== null;
- renderExpirationTime = NoWork;
+ renderLanes = NoLanes;
currentlyRenderingFiber = (null: any);
currentHook = null;
@@ -480,13 +480,11 @@ export function renderWithHooks(
export function bailoutHooks(
current: Fiber,
workInProgress: Fiber,
- expirationTime: ExpirationTimeOpaque,
+ lanes: Lanes,
) {
workInProgress.updateQueue = current.updateQueue;
workInProgress.effectTag &= ~(PassiveEffect | UpdateEffect);
- if (isSameOrHigherPriority(expirationTime, current.expirationTime_opaque)) {
- current.expirationTime_opaque = NoWork;
- }
+ current.lanes = removeLanes(current.lanes, lanes);
}
export function resetHooksAfterThrow(): void {
@@ -514,7 +512,7 @@ export function resetHooksAfterThrow(): void {
didScheduleRenderPhaseUpdate = false;
}
- renderExpirationTime = NoWork;
+ renderLanes = NoLanes;
currentlyRenderingFiber = (null: any);
currentHook = null;
@@ -708,15 +706,15 @@ function updateReducer(
let update = first;
do {
const suspenseConfig = update.suspenseConfig;
- const updateExpirationTime = update.expirationTime;
+ const updateLane = update.lane;
const updateEventTime = update.eventTime;
- if (!isSameOrHigherPriority(updateExpirationTime, renderExpirationTime)) {
+ if (!isSubsetOfLanes(renderLanes, updateLane)) {
// Priority is insufficient. Skip this update. If this is the first
// skipped update, the previous update/state is the new base
// update/state.
const clone: Update = {
eventTime: updateEventTime,
- expirationTime: updateExpirationTime,
+ lane: updateLane,
suspenseConfig: suspenseConfig,
action: update.action,
eagerReducer: update.eagerReducer,
@@ -730,22 +728,23 @@ function updateReducer(
newBaseQueueLast = newBaseQueueLast.next = clone;
}
// Update the remaining priority in the queue.
- if (
- !isSameOrHigherPriority(
- currentlyRenderingFiber.expirationTime_opaque,
- updateExpirationTime,
- )
- ) {
- currentlyRenderingFiber.expirationTime_opaque = updateExpirationTime;
- markUnprocessedUpdateTime(updateExpirationTime);
- }
+ // TODO: Don't need to accumulate this. Instead, we can remove
+ // renderLanes from the original lanes.
+ currentlyRenderingFiber.lanes = combineLanes(
+ currentlyRenderingFiber.lanes,
+ updateLane,
+ );
+ markSkippedUpdateLanes(updateLane);
} else {
// This update does have sufficient priority.
if (newBaseQueueLast !== null) {
const clone: Update = {
eventTime: updateEventTime,
- expirationTime: Sync, // This update is going to be committed so we never want uncommit it.
+ // This update is going to be committed so we never want uncommit
+ // it. Using NoLane works because 0 is a subset of all bitmasks, so
+ // this will never be skipped by the check above.
+ lane: NoLane,
suspenseConfig: update.suspenseConfig,
action: update.action,
eagerReducer: update.eagerReducer,
@@ -884,24 +883,14 @@ function readFromUnsubcribedMutableSource