diff --git a/packages/react-reconciler/src/ReactChildFiber.js b/packages/react-reconciler/src/ReactChildFiber.js index f574162b41b..3bde0d6db9a 100644 --- a/packages/react-reconciler/src/ReactChildFiber.js +++ b/packages/react-reconciler/src/ReactChildFiber.js @@ -68,9 +68,9 @@ import { SuspenseActionException, createThenableState, trackUsedThenable, + resolveLazy, } from './ReactFiberThenable'; import {readContextDuringReconciliation} from './ReactFiberNewContext'; -import {callLazyInitInDEV} from './ReactFiberCallUserSpace'; import {runWithFiberInDEV} from './ReactCurrentFiber'; @@ -364,15 +364,6 @@ function warnOnSymbolType(returnFiber: Fiber, invalidChild: symbol) { } } -function resolveLazy(lazyType: any) { - if (__DEV__) { - return callLazyInitInDEV(lazyType); - } - const payload = lazyType._payload; - const init = lazyType._init; - return init(payload); -} - type ChildReconciler = ( returnFiber: Fiber, currentFirstChild: Fiber | null, @@ -698,14 +689,7 @@ function createChildReconciler( } case REACT_LAZY_TYPE: { const prevDebugInfo = pushDebugInfo(newChild._debugInfo); - let resolvedChild; - if (__DEV__) { - resolvedChild = callLazyInitInDEV(newChild); - } else { - const payload = newChild._payload; - const init = newChild._init; - resolvedChild = init(payload); - } + const resolvedChild = resolveLazy((newChild: any)); const created = createChild(returnFiber, resolvedChild, lanes); currentDebugInfo = prevDebugInfo; return created; @@ -830,14 +814,7 @@ function createChildReconciler( } case REACT_LAZY_TYPE: { const prevDebugInfo = pushDebugInfo(newChild._debugInfo); - let resolvedChild; - if (__DEV__) { - resolvedChild = callLazyInitInDEV(newChild); - } else { - const payload = newChild._payload; - const init = newChild._init; - resolvedChild = init(payload); - } + const resolvedChild = resolveLazy((newChild: any)); const updated = updateSlot( returnFiber, oldFiber, @@ -962,14 +939,7 @@ function createChildReconciler( } case REACT_LAZY_TYPE: { const prevDebugInfo = pushDebugInfo(newChild._debugInfo); - let resolvedChild; - if (__DEV__) { - resolvedChild = callLazyInitInDEV(newChild); - } else { - const payload = newChild._payload; - const init = newChild._init; - resolvedChild = init(payload); - } + const resolvedChild = resolveLazy((newChild: any)); const updated = updateFromMap( existingChildren, returnFiber, @@ -1086,14 +1056,7 @@ function createChildReconciler( }); break; case REACT_LAZY_TYPE: { - let resolvedChild; - if (__DEV__) { - resolvedChild = callLazyInitInDEV((child: any)); - } else { - const payload = child._payload; - const init = (child._init: any); - resolvedChild = init(payload); - } + const resolvedChild = resolveLazy((child: any)); warnOnInvalidKey( returnFiber, workInProgress, @@ -1809,14 +1772,7 @@ function createChildReconciler( ); case REACT_LAZY_TYPE: { const prevDebugInfo = pushDebugInfo(newChild._debugInfo); - let result; - if (__DEV__) { - result = callLazyInitInDEV(newChild); - } else { - const payload = newChild._payload; - const init = newChild._init; - result = init(payload); - } + const result = resolveLazy((newChild: any)); const firstChild = reconcileChildFibersImpl( returnFiber, currentFirstChild, diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js index 372bab95cea..33b9e79edfa 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.js @@ -302,11 +302,8 @@ import { pushRootMarkerInstance, TransitionTracingMarker, } from './ReactFiberTracingMarkerComponent'; -import { - callLazyInitInDEV, - callComponentInDEV, - callRenderInDEV, -} from './ReactFiberCallUserSpace'; +import {callComponentInDEV, callRenderInDEV} from './ReactFiberCallUserSpace'; +import {resolveLazy} from './ReactFiberThenable'; // A special exception that's used to unwind the stack when an update flows // into a dehydrated boundary. @@ -2020,14 +2017,7 @@ function mountLazyComponent( const props = workInProgress.pendingProps; const lazyComponent: LazyComponentType = elementType; - let Component; - if (__DEV__) { - Component = callLazyInitInDEV(lazyComponent); - } else { - const payload = lazyComponent._payload; - const init = lazyComponent._init; - Component = init(payload); - } + let Component = resolveLazy(lazyComponent); // Store the unwrapped component in the type. workInProgress.type = Component; diff --git a/packages/react-reconciler/src/ReactFiberThenable.js b/packages/react-reconciler/src/ReactFiberThenable.js index 4f52131a649..f4ae1d45b27 100644 --- a/packages/react-reconciler/src/ReactFiberThenable.js +++ b/packages/react-reconciler/src/ReactFiberThenable.js @@ -14,6 +14,10 @@ import type { RejectedThenable, } from 'shared/ReactTypes'; +import type {LazyComponent as LazyComponentType} from 'react/src/ReactLazy'; + +import {callLazyInitInDEV} from './ReactFiberCallUserSpace'; + import {getWorkInProgressRoot} from './ReactFiberWorkLoop'; import ReactSharedInternals from 'shared/ReactSharedInternals'; @@ -260,6 +264,27 @@ export function suspendCommit(): void { throw SuspenseyCommitException; } +export function resolveLazy(lazyType: LazyComponentType): T { + try { + if (__DEV__) { + return callLazyInitInDEV(lazyType); + } + const payload = lazyType._payload; + const init = lazyType._init; + return init(payload); + } catch (x) { + if (x !== null && typeof x === 'object' && typeof x.then === 'function') { + // This lazy Suspended. Treat this as if we called use() to unwrap it. + suspendedThenable = x; + if (__DEV__) { + needsToResetSuspendedThenableDEV = true; + } + throw SuspenseException; + } + throw x; + } +} + // This is used to track the actual thenable that suspended so it can be // passed to the rest of the Suspense implementation — which, for historical // reasons, expects to receive a thenable. diff --git a/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js b/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js index 27404eee5e2..e594e4fbedb 100644 --- a/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js @@ -198,10 +198,7 @@ describe('ReactLazy', () => { await resolveFakeImport(Foo); - await waitForAll([ - 'Foo', - ...(gate('alwaysThrottleRetries') ? [] : ['Foo']), - ]); + await waitForAll(['Foo']); expect(root).not.toMatchRenderedOutput('FooBar'); await act(() => resolveFakeImport(Bar)); @@ -1329,11 +1326,7 @@ describe('ReactLazy', () => { expect(ref.current).toBe(null); await act(() => resolveFakeImport(Foo)); - assertLog([ - 'Foo', - // pre-warming - 'Foo', - ]); + assertLog(['Foo']); await act(() => resolveFakeImport(ForwardRefBar)); assertLog(['Foo', 'forwardRef', 'Bar']); @@ -1493,11 +1486,7 @@ describe('ReactLazy', () => { expect(root).not.toMatchRenderedOutput('AB'); await act(() => resolveFakeImport(ChildA)); - assertLog([ - 'A', - // pre-warming - 'A', - ]); + assertLog(['A']); await act(() => resolveFakeImport(ChildB)); assertLog(['A', 'B', 'Did mount: A', 'Did mount: B']);