From aedc6badf119868db08833408c266ff08fce262c Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Fri, 19 Oct 2018 17:41:59 -0700 Subject: [PATCH 1/7] Introduce elementType field This will be used to store the wrapped type of an element. E.g. pure and lazy. The existing type field will be used for the unwrapped type within them. --- .../react-reconciler/src/ReactChildFiber.js | 4 +- packages/react-reconciler/src/ReactFiber.js | 103 +++++++++++++++--- .../src/ReactFiberBeginWork.js | 19 ++-- 3 files changed, 102 insertions(+), 24 deletions(-) diff --git a/packages/react-reconciler/src/ReactChildFiber.js b/packages/react-reconciler/src/ReactChildFiber.js index 4151b0061384c..9c6b6b76cba75 100644 --- a/packages/react-reconciler/src/ReactChildFiber.js +++ b/packages/react-reconciler/src/ReactChildFiber.js @@ -379,7 +379,7 @@ function ChildReconciler(shouldTrackSideEffects) { element: ReactElement, expirationTime: ExpirationTime, ): Fiber { - if (current !== null && current.type === element.type) { + if (current !== null && current.elementType === element.type) { // Move based on index const existing = useFiber(current, element.props, expirationTime); existing.ref = coerceRef(returnFiber, current, element); @@ -1122,7 +1122,7 @@ function ChildReconciler(shouldTrackSideEffects) { if ( child.tag === Fragment ? element.type === REACT_FRAGMENT_TYPE - : child.type === element.type + : child.elementType === element.type ) { deleteRemainingChildren(returnFiber, child.sibling); const existing = useFiber( diff --git a/packages/react-reconciler/src/ReactFiber.js b/packages/react-reconciler/src/ReactFiber.js index 3ad8fccdcddfa..77845a80c1751 100644 --- a/packages/react-reconciler/src/ReactFiber.js +++ b/packages/react-reconciler/src/ReactFiber.js @@ -101,7 +101,11 @@ export type Fiber = {| // Unique identifier of this child. key: null | string, - // The function/class/module associated with this fiber. + // The value of element.type which is used to preserve the identity during + // reconciliation of this child. + elementType: any, + + // The resolved function/class/ associated with this fiber. type: any, // The local state associated with this fiber. @@ -219,6 +223,7 @@ function FiberNode( // Instance this.tag = tag; this.key = key; + this.elementType = null; this.type = null; this.stateNode = null; @@ -335,6 +340,7 @@ export function createWorkInProgress( current.key, current.mode, ); + workInProgress.elementType = current.elementType; workInProgress.type = current.type; workInProgress.stateNode = current.stateNode; @@ -404,7 +410,7 @@ export function createHostRootFiber(isConcurrent: boolean): Fiber { return createFiber(HostRoot, null, null, mode); } -export function createFiberFromElement( +function createFiberFromElementWithoutDebugInfo( element: ReactElement, mode: TypeOfMode, expirationTime: ExpirationTime, @@ -419,9 +425,15 @@ export function createFiberFromElement( const key = element.key; const pendingProps = element.props; - let fiberTag; + let fiberTag = IndeterminateComponent; + // The resolved type is set if we know what the final type will be. I.e. it's not indeterminate. + let resolvedType = type; if (typeof type === 'function') { - fiberTag = shouldConstruct(type) ? ClassComponent : IndeterminateComponent; + if (shouldConstruct(type)) { + fiberTag = ClassComponent; + } else { + resolvedType = null; + } } else if (typeof type === 'string') { fiberTag = HostComponent; } else { @@ -434,18 +446,23 @@ export function createFiberFromElement( key, ); case REACT_CONCURRENT_MODE_TYPE: - fiberTag = Mode; - mode |= ConcurrentMode | StrictMode; - break; + return createFiberFromMode( + pendingProps, + mode | ConcurrentMode | StrictMode, + expirationTime, + key, + ); case REACT_STRICT_MODE_TYPE: - fiberTag = Mode; - mode |= StrictMode; - break; + return createFiberFromMode( + pendingProps, + mode | StrictMode, + expirationTime, + key, + ); case REACT_PROFILER_TYPE: return createFiberFromProfiler(pendingProps, mode, expirationTime, key); case REACT_SUSPENSE_TYPE: - fiberTag = SuspenseComponent; - break; + return createFiberFromSuspense(pendingProps, mode, expirationTime, key); default: { if (typeof type === 'object' && type !== null) { switch (type.$$typeof) { @@ -464,6 +481,7 @@ export function createFiberFromElement( break getTag; case REACT_LAZY_TYPE: fiberTag = IndeterminateComponent; + resolvedType = null; break getTag; } } @@ -498,14 +516,27 @@ export function createFiberFromElement( } fiber = createFiber(fiberTag, pendingProps, key, mode); - fiber.type = type; + fiber.elementType = type; + fiber.type = resolvedType; fiber.expirationTime = expirationTime; + return fiber; +} + +export function createFiberFromElement( + element: ReactElement, + mode: TypeOfMode, + expirationTime: ExpirationTime, +): Fiber { + const fiber = createFiberFromElementWithoutDebugInfo( + element, + mode, + expirationTime, + ); if (__DEV__) { fiber._debugSource = element._source; fiber._debugOwner = element._owner; } - return fiber; } @@ -520,7 +551,7 @@ export function createFiberFromFragment( return fiber; } -export function createFiberFromProfiler( +function createFiberFromProfiler( pendingProps: any, mode: TypeOfMode, expirationTime: ExpirationTime, @@ -539,12 +570,51 @@ export function createFiberFromProfiler( } const fiber = createFiber(Profiler, pendingProps, key, mode | ProfileMode); + // 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 = expirationTime; return fiber; } +function createFiberFromMode( + pendingProps: any, + mode: TypeOfMode, + expirationTime: ExpirationTime, + key: null | string, +): Fiber { + const fiber = createFiber(Mode, pendingProps, key, mode); + + // TODO: The Mode fiber shouldn't have a type. It has a tag. + const type = + (mode & ConcurrentMode) === NoContext + ? REACT_STRICT_MODE_TYPE + : REACT_CONCURRENT_MODE_TYPE; + fiber.elementType = type; + fiber.type = type; + + fiber.expirationTime = expirationTime; + return fiber; +} + +export function createFiberFromSuspense( + pendingProps: any, + mode: TypeOfMode, + expirationTime: ExpirationTime, + key: null | string, +) { + const fiber = createFiber(SuspenseComponent, pendingProps, key, mode); + + // TODO: The SuspenseComponent fiber shouldn't have a type. It has a tag. + const type = REACT_SUSPENSE_TYPE; + fiber.elementType = type; + fiber.type = type; + + fiber.expirationTime = expirationTime; + return fiber; +} + export function createFiberFromText( content: string, mode: TypeOfMode, @@ -557,6 +627,8 @@ export function createFiberFromText( export function createFiberFromHostInstanceForDeletion(): Fiber { const fiber = createFiber(HostComponent, null, null, NoContext); + // TODO: These should not need a type. + fiber.elementType = 'DELETED'; fiber.type = 'DELETED'; return fiber; } @@ -596,6 +668,7 @@ export function assignFiberPropertiesInDEV( target.tag = source.tag; target.key = source.key; + target.elementType = source.elementType; target.type = source.type; target.stateNode = source.stateNode; target.return = source.return; diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js index c51869ab659ef..d70b46659511f 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.js @@ -708,7 +708,7 @@ function resolveDefaultProps(Component, baseProps) { function mountIndeterminateComponent( _current, workInProgress, - Component, + elementType, updateExpirationTime, renderExpirationTime, ) { @@ -724,15 +724,18 @@ function mountIndeterminateComponent( } const props = workInProgress.pendingProps; + let Component; + // TODO: This will be storing the unwrapped value insteads. + workInProgress.type = elementType; if ( - typeof Component === 'object' && - Component !== null && - Component.$$typeof === REACT_LAZY_TYPE + typeof elementType === 'object' && + elementType !== null && + elementType.$$typeof === REACT_LAZY_TYPE ) { // We can't start a User Timing measurement with correct label yet. // Cancel and resume right after we know the tag. cancelWorkTimer(workInProgress); - Component = readLazyComponentType(Component); + Component = readLazyComponentType(elementType); const resolvedTag = (workInProgress.tag = resolveLazyComponentTag( workInProgress, Component, @@ -795,6 +798,8 @@ function mountIndeterminateComponent( } } return child; + } else { + Component = elementType; } const unmaskedContext = getUnmaskedContext(workInProgress, Component, false); @@ -1457,11 +1462,11 @@ function beginWork( switch (workInProgress.tag) { case IndeterminateComponent: { - const Component = workInProgress.type; + const elementType = workInProgress.elementType; return mountIndeterminateComponent( current, workInProgress, - Component, + elementType, updateExpirationTime, renderExpirationTime, ); From 4949da90ecaa3b5240dfa561253a58038e423942 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Fri, 19 Oct 2018 18:47:21 -0700 Subject: [PATCH 2/7] Store the unwrapped type on the type field of lazy components --- packages/react-reconciler/src/ReactFiber.js | 4 +--- .../src/ReactFiberBeginWork.js | 21 +++++++------------ .../src/ReactFiberCompleteWork.js | 3 +-- .../react-reconciler/src/ReactFiberContext.js | 3 +-- .../src/ReactFiberReconciler.js | 3 +-- .../src/ReactFiberScheduler.js | 5 +---- packages/shared/ReactLazyComponent.js | 6 ------ 7 files changed, 13 insertions(+), 32 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiber.js b/packages/react-reconciler/src/ReactFiber.js index 77845a80c1751..60797ab07b4cf 100644 --- a/packages/react-reconciler/src/ReactFiber.js +++ b/packages/react-reconciler/src/ReactFiber.js @@ -426,13 +426,11 @@ function createFiberFromElementWithoutDebugInfo( const pendingProps = element.props; let fiberTag = IndeterminateComponent; - // The resolved type is set if we know what the final type will be. I.e. it's not indeterminate. + // The resolved type is set if we know what the final type will be. I.e. it's not lazy. let resolvedType = type; if (typeof type === 'function') { if (shouldConstruct(type)) { fiberTag = ClassComponent; - } else { - resolvedType = null; } } else if (typeof type === 'string') { fiberTag = HostComponent; diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js index d70b46659511f..02897b557e43c 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.js @@ -104,7 +104,6 @@ import { updateClassInstance, } from './ReactFiberClassComponent'; import {readLazyComponentType} from './ReactFiberLazyComponent'; -import {getResultFromResolvedLazyComponent} from 'shared/ReactLazyComponent'; import { resolveLazyComponentTag, createFiberFromFragment, @@ -725,8 +724,6 @@ function mountIndeterminateComponent( const props = workInProgress.pendingProps; let Component; - // TODO: This will be storing the unwrapped value insteads. - workInProgress.type = elementType; if ( typeof elementType === 'object' && elementType !== null && @@ -736,6 +733,8 @@ function mountIndeterminateComponent( // Cancel and resume right after we know the tag. cancelWorkTimer(workInProgress); Component = readLazyComponentType(elementType); + // Store the unwrapped component in the type. + workInProgress.type = Component; const resolvedTag = (workInProgress.tag = resolveLazyComponentTag( workInProgress, Component, @@ -799,6 +798,7 @@ function mountIndeterminateComponent( } return child; } else { + workInProgress.type = elementType; Component = elementType; } @@ -1407,8 +1407,7 @@ function beginWork( break; } case ClassComponentLazy: { - const thenable = workInProgress.type; - const Component = getResultFromResolvedLazyComponent(thenable); + const Component = workInProgress.type; if (isLegacyContextProvider(Component)) { pushLegacyContextProvider(workInProgress); } @@ -1483,8 +1482,7 @@ function beginWork( ); } case FunctionComponentLazy: { - const thenable = workInProgress.type; - const Component = getResultFromResolvedLazyComponent(thenable); + const Component = workInProgress.type; const unresolvedProps = workInProgress.pendingProps; const child = updateFunctionComponent( current, @@ -1507,8 +1505,7 @@ function beginWork( ); } case ClassComponentLazy: { - const thenable = workInProgress.type; - const Component = getResultFromResolvedLazyComponent(thenable); + const Component = workInProgress.type; const unresolvedProps = workInProgress.pendingProps; const child = updateClassComponent( current, @@ -1548,8 +1545,7 @@ function beginWork( ); } case ForwardRefLazy: { - const thenable = workInProgress.type; - const Component = getResultFromResolvedLazyComponent(thenable); + const Component = workInProgress.type; const unresolvedProps = workInProgress.pendingProps; const child = updateForwardRef( current, @@ -1590,8 +1586,7 @@ function beginWork( ); } case PureComponentLazy: { - const thenable = workInProgress.type; - const Component = getResultFromResolvedLazyComponent(thenable); + const Component = workInProgress.type; const unresolvedProps = workInProgress.pendingProps; const child = updatePureComponent( current, diff --git a/packages/react-reconciler/src/ReactFiberCompleteWork.js b/packages/react-reconciler/src/ReactFiberCompleteWork.js index d13bd2c66b8df..a5d16facc3831 100644 --- a/packages/react-reconciler/src/ReactFiberCompleteWork.js +++ b/packages/react-reconciler/src/ReactFiberCompleteWork.js @@ -42,7 +42,6 @@ import { } from 'shared/ReactWorkTags'; import {Placement, Ref, Update} from 'shared/ReactSideEffectTags'; import invariant from 'shared/invariant'; -import {getResultFromResolvedLazyComponent} from 'shared/ReactLazyComponent'; import { createInstance, @@ -552,7 +551,7 @@ function completeWork( break; } case ClassComponentLazy: { - const Component = getResultFromResolvedLazyComponent(workInProgress.type); + const Component = workInProgress.type; if (isLegacyContextProvider(Component)) { popLegacyContext(workInProgress); } diff --git a/packages/react-reconciler/src/ReactFiberContext.js b/packages/react-reconciler/src/ReactFiberContext.js index 4ef224e2636f2..da8accc11c954 100644 --- a/packages/react-reconciler/src/ReactFiberContext.js +++ b/packages/react-reconciler/src/ReactFiberContext.js @@ -20,7 +20,6 @@ import getComponentName from 'shared/getComponentName'; import invariant from 'shared/invariant'; import warningWithoutStack from 'shared/warningWithoutStack'; import checkPropTypes from 'prop-types/checkPropTypes'; -import {getResultFromResolvedLazyComponent} from 'shared/ReactLazyComponent'; import * as ReactCurrentFiber from './ReactCurrentFiber'; import {startPhaseTimer, stopPhaseTimer} from './ReactDebugFiberPerf'; @@ -298,7 +297,7 @@ function findCurrentUnmaskedContext(fiber: Fiber): Object { break; } case ClassComponentLazy: { - const Component = getResultFromResolvedLazyComponent(node.type); + const Component = node.type; if (isContextProvider(Component)) { return node.stateNode.__reactInternalMemoizedMergedChildContext; } diff --git a/packages/react-reconciler/src/ReactFiberReconciler.js b/packages/react-reconciler/src/ReactFiberReconciler.js index 75a7efb59b111..3c47f7da968ad 100644 --- a/packages/react-reconciler/src/ReactFiberReconciler.js +++ b/packages/react-reconciler/src/ReactFiberReconciler.js @@ -31,7 +31,6 @@ import { import getComponentName from 'shared/getComponentName'; import invariant from 'shared/invariant'; import warningWithoutStack from 'shared/warningWithoutStack'; -import {getResultFromResolvedLazyComponent} from 'shared/ReactLazyComponent'; import {getPublicInstance} from './ReactFiberHostConfig'; import { @@ -107,7 +106,7 @@ function getContextForSubtree( return processChildContext(fiber, Component, parentContext); } } else if (fiber.tag === ClassComponentLazy) { - const Component = getResultFromResolvedLazyComponent(fiber.type); + const Component = fiber.type; if (isLegacyContextProvider(Component)) { return processChildContext(fiber, Component, parentContext); } diff --git a/packages/react-reconciler/src/ReactFiberScheduler.js b/packages/react-reconciler/src/ReactFiberScheduler.js index d81dc34e7104a..beaf5daf21404 100644 --- a/packages/react-reconciler/src/ReactFiberScheduler.js +++ b/packages/react-reconciler/src/ReactFiberScheduler.js @@ -53,7 +53,6 @@ import { import getComponentName from 'shared/getComponentName'; import invariant from 'shared/invariant'; import warningWithoutStack from 'shared/warningWithoutStack'; -import {getResultFromResolvedLazyComponent} from 'shared/ReactLazyComponent'; import { scheduleTimeout, @@ -317,9 +316,7 @@ if (__DEV__ && replayFailedUnitOfWorkWithInvokeGuardedCallback) { break; } case ClassComponentLazy: { - const Component = getResultFromResolvedLazyComponent( - failedUnitOfWork.type, - ); + const Component = failedUnitOfWork.type; if (isLegacyContextProvider(Component)) { popLegacyContext(failedUnitOfWork); } diff --git a/packages/shared/ReactLazyComponent.js b/packages/shared/ReactLazyComponent.js index b44620172a723..f3042ab11aec4 100644 --- a/packages/shared/ReactLazyComponent.js +++ b/packages/shared/ReactLazyComponent.js @@ -29,12 +29,6 @@ export const Pending = 0; export const Resolved = 1; export const Rejected = 2; -export function getResultFromResolvedLazyComponent( - lazyComponent: ResolvedLazyComponent, -): T { - return lazyComponent._result; -} - export function refineResolvedLazyComponent( lazyComponent: LazyComponent, ): ResolvedLazyComponent | null { From 2e074110902b1da10d378b4b3e454d03cf2b7cba Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Fri, 19 Oct 2018 19:05:41 -0700 Subject: [PATCH 3/7] Use the raw tags for lazy components Instead, we check if the elementType and type are equal to test if we need to resolve props. This is slightly slower in the normal case but will yield less code and branching. --- packages/react-reconciler/src/ReactFiber.js | 13 +-- .../src/ReactFiberBeginWork.js | 93 ++++++------------- .../src/__tests__/ReactLazy-test.internal.js | 2 +- 3 files changed, 31 insertions(+), 77 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiber.js b/packages/react-reconciler/src/ReactFiber.js index 60797ab07b4cf..4876ee44cce4a 100644 --- a/packages/react-reconciler/src/ReactFiber.js +++ b/packages/react-reconciler/src/ReactFiber.js @@ -34,11 +34,8 @@ import { ContextConsumer, Profiler, SuspenseComponent, - FunctionComponentLazy, - ClassComponentLazy, - ForwardRefLazy, + FunctionComponent, PureComponent, - PureComponentLazy, } from 'shared/ReactWorkTags'; import getComponentName from 'shared/getComponentName'; @@ -306,16 +303,14 @@ export function resolveLazyComponentTag( Component: Function, ): WorkTag { if (typeof Component === 'function') { - return shouldConstruct(Component) - ? ClassComponentLazy - : FunctionComponentLazy; + return shouldConstruct(Component) ? ClassComponent : FunctionComponent; } else if (Component !== undefined && Component !== null) { const $$typeof = Component.$$typeof; if ($$typeof === REACT_FORWARD_REF_TYPE) { - return ForwardRefLazy; + return ForwardRef; } if ($$typeof === REACT_PURE_TYPE) { - return PureComponentLazy; + return PureComponent; } } return IndeterminateComponent; diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js index 02897b557e43c..c290721b6a208 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.js @@ -18,7 +18,6 @@ import checkPropTypes from 'prop-types/checkPropTypes'; import { IndeterminateComponent, FunctionComponent, - FunctionComponentLazy, ClassComponent, ClassComponentLazy, HostRoot, @@ -26,7 +25,6 @@ import { HostText, HostPortal, ForwardRef, - ForwardRefLazy, Fragment, Mode, ContextProvider, @@ -34,7 +32,6 @@ import { Profiler, SuspenseComponent, PureComponent, - PureComponentLazy, } from 'shared/ReactWorkTags'; import { NoEffect, @@ -743,7 +740,7 @@ function mountIndeterminateComponent( const resolvedProps = resolveDefaultProps(Component, props); let child; switch (resolvedTag) { - case FunctionComponentLazy: { + case FunctionComponent: { child = updateFunctionComponent( null, workInProgress, @@ -753,7 +750,7 @@ function mountIndeterminateComponent( ); break; } - case ClassComponentLazy: { + case ClassComponent: { child = updateClassComponent( null, workInProgress, @@ -763,7 +760,7 @@ function mountIndeterminateComponent( ); break; } - case ForwardRefLazy: { + case ForwardRef: { child = updateForwardRef( null, workInProgress, @@ -773,7 +770,7 @@ function mountIndeterminateComponent( ); break; } - case PureComponentLazy: { + case PureComponent: { child = updatePureComponent( null, workInProgress, @@ -1406,13 +1403,6 @@ function beginWork( } break; } - case ClassComponentLazy: { - const Component = workInProgress.type; - if (isLegacyContextProvider(Component)) { - pushLegacyContextProvider(workInProgress); - } - break; - } case HostPortal: pushHostContainer( workInProgress, @@ -1473,49 +1463,33 @@ function beginWork( case FunctionComponent: { const Component = workInProgress.type; const unresolvedProps = workInProgress.pendingProps; + const resolvedProps = + workInProgress.elementType === Component + ? unresolvedProps + : resolveDefaultProps(Component, unresolvedProps); return updateFunctionComponent( current, workInProgress, Component, - unresolvedProps, + resolvedProps, renderExpirationTime, ); } - case FunctionComponentLazy: { - const Component = workInProgress.type; - const unresolvedProps = workInProgress.pendingProps; - const child = updateFunctionComponent( - current, - workInProgress, - Component, - resolveDefaultProps(Component, unresolvedProps), - renderExpirationTime, - ); - return child; - } case ClassComponent: { const Component = workInProgress.type; const unresolvedProps = workInProgress.pendingProps; + const resolvedProps = + workInProgress.elementType === Component + ? unresolvedProps + : resolveDefaultProps(Component, unresolvedProps); return updateClassComponent( current, workInProgress, Component, - unresolvedProps, + resolvedProps, renderExpirationTime, ); } - case ClassComponentLazy: { - const Component = workInProgress.type; - const unresolvedProps = workInProgress.pendingProps; - const child = updateClassComponent( - current, - workInProgress, - Component, - resolveDefaultProps(Component, unresolvedProps), - renderExpirationTime, - ); - return child; - } case HostRoot: return updateHostRoot(current, workInProgress, renderExpirationTime); case HostComponent: @@ -1536,25 +1510,18 @@ function beginWork( ); case ForwardRef: { const type = workInProgress.type; + const unresolvedProps = workInProgress.pendingProps; + const resolvedProps = + workInProgress.elementType === type + ? unresolvedProps + : resolveDefaultProps(type, unresolvedProps); return updateForwardRef( current, workInProgress, type, - workInProgress.pendingProps, - renderExpirationTime, - ); - } - case ForwardRefLazy: { - const Component = workInProgress.type; - const unresolvedProps = workInProgress.pendingProps; - const child = updateForwardRef( - current, - workInProgress, - Component, - resolveDefaultProps(Component, unresolvedProps), + resolvedProps, renderExpirationTime, ); - return child; } case Fragment: return updateFragment(current, workInProgress, renderExpirationTime); @@ -1576,27 +1543,19 @@ function beginWork( ); case PureComponent: { const type = workInProgress.type; + const unresolvedProps = workInProgress.pendingProps; + const resolvedProps = + workInProgress.elementType === type + ? unresolvedProps + : resolveDefaultProps(type, unresolvedProps); return updatePureComponent( current, workInProgress, type, - workInProgress.pendingProps, - updateExpirationTime, - renderExpirationTime, - ); - } - case PureComponentLazy: { - const Component = workInProgress.type; - const unresolvedProps = workInProgress.pendingProps; - const child = updatePureComponent( - current, - workInProgress, - Component, - resolveDefaultProps(Component, unresolvedProps), + resolvedProps, updateExpirationTime, renderExpirationTime, ); - return child; } default: invariant( diff --git a/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js b/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js index 9179f9dac44cf..11b270d65fec7 100644 --- a/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js @@ -229,7 +229,7 @@ describe('ReactLazy', () => { T.defaultProps = {text: 'Hi again'}; root.update( }> - + , ); expect(root).toFlushAndYield(['Hi again']); From 0f75e25ba26bcf7da66ebd2b1a1d4535ff445186 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Fri, 19 Oct 2018 19:50:05 -0700 Subject: [PATCH 4/7] Clean up lazy branches --- .../src/test-utils/ReactTestUtils.js | 6 +--- .../react-reconciler/src/ReactChildFiber.js | 7 ++-- .../react-reconciler/src/ReactCurrentFiber.js | 4 --- .../src/ReactFiberBeginWork.js | 1 - .../src/ReactFiberCommitWork.js | 17 +++------- .../src/ReactFiberCompleteWork.js | 15 --------- .../react-reconciler/src/ReactFiberContext.js | 16 ++-------- .../src/ReactFiberNewContext.js | 11 ++----- .../src/ReactFiberReconciler.js | 11 +------ .../src/ReactFiberScheduler.js | 16 ++-------- .../src/ReactFiberTreeReflection.js | 6 +--- .../src/ReactFiberUnwindWork.js | 27 +--------------- .../react-reconciler/src/ReactUpdateQueue.js | 4 +-- .../src/ReactTestRenderer.js | 32 ------------------- packages/shared/ReactWorkTags.js | 4 --- 15 files changed, 19 insertions(+), 158 deletions(-) diff --git a/packages/react-dom/src/test-utils/ReactTestUtils.js b/packages/react-dom/src/test-utils/ReactTestUtils.js index 4c7ad289fbaa9..73c5944d51667 100644 --- a/packages/react-dom/src/test-utils/ReactTestUtils.js +++ b/packages/react-dom/src/test-utils/ReactTestUtils.js @@ -11,9 +11,7 @@ import {findCurrentFiberUsingSlowPath} from 'react-reconciler/reflection'; import * as ReactInstanceMap from 'shared/ReactInstanceMap'; import { ClassComponent, - ClassComponentLazy, FunctionComponent, - FunctionComponentLazy, HostComponent, HostText, } from 'shared/ReactWorkTags'; @@ -92,9 +90,7 @@ function findAllInRenderedFiberTreeInternal(fiber, test) { node.tag === HostComponent || node.tag === HostText || node.tag === ClassComponent || - node.tag === ClassComponentLazy || - node.tag === FunctionComponent || - node.tag === FunctionComponentLazy + node.tag === FunctionComponent ) { const publicInst = node.stateNode; if (test(publicInst)) { diff --git a/packages/react-reconciler/src/ReactChildFiber.js b/packages/react-reconciler/src/ReactChildFiber.js index 9c6b6b76cba75..2cf9791f8a2d7 100644 --- a/packages/react-reconciler/src/ReactChildFiber.js +++ b/packages/react-reconciler/src/ReactChildFiber.js @@ -23,7 +23,6 @@ import { import { FunctionComponent, ClassComponent, - ClassComponentLazy, HostText, HostPortal, Fragment, @@ -138,8 +137,7 @@ function coerceRef( if (owner) { const ownerFiber = ((owner: any): Fiber); invariant( - ownerFiber.tag === ClassComponent || - ownerFiber.tag === ClassComponentLazy, + ownerFiber.tag === ClassComponent, 'Function components cannot have refs.', ); inst = ownerFiber.stateNode; @@ -1309,8 +1307,7 @@ function ChildReconciler(shouldTrackSideEffects) { // component, throw an error. If Fiber return types are disabled, // we already threw above. switch (returnFiber.tag) { - case ClassComponent: - case ClassComponentLazy: { + case ClassComponent: { if (__DEV__) { const instance = returnFiber.stateNode; if (instance.render._isMockFunction) { diff --git a/packages/react-reconciler/src/ReactCurrentFiber.js b/packages/react-reconciler/src/ReactCurrentFiber.js index 378d3441ea119..ea52ec292e12b 100644 --- a/packages/react-reconciler/src/ReactCurrentFiber.js +++ b/packages/react-reconciler/src/ReactCurrentFiber.js @@ -11,9 +11,7 @@ import ReactSharedInternals from 'shared/ReactSharedInternals'; import { IndeterminateComponent, FunctionComponent, - FunctionComponentLazy, ClassComponent, - ClassComponentLazy, HostComponent, Mode, } from 'shared/ReactWorkTags'; @@ -30,9 +28,7 @@ function describeFiber(fiber: Fiber): string { switch (fiber.tag) { case IndeterminateComponent: case FunctionComponent: - case FunctionComponentLazy: case ClassComponent: - case ClassComponentLazy: case HostComponent: case Mode: const owner = fiber._debugOwner; diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js index c290721b6a208..6dbca81603d1e 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.js @@ -19,7 +19,6 @@ import { IndeterminateComponent, FunctionComponent, ClassComponent, - ClassComponentLazy, HostRoot, HostComponent, HostText, diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.js b/packages/react-reconciler/src/ReactFiberCommitWork.js index 36d4045d133ad..b79c36f648120 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.js @@ -26,7 +26,6 @@ import { } from 'shared/ReactFeatureFlags'; import { ClassComponent, - ClassComponentLazy, HostRoot, HostComponent, HostText, @@ -185,8 +184,7 @@ function commitBeforeMutationLifeCycles( finishedWork: Fiber, ): void { switch (finishedWork.tag) { - case ClassComponent: - case ClassComponentLazy: { + case ClassComponent: { if (finishedWork.effectTag & Snapshot) { if (current !== null) { const prevProps = current.memoizedProps; @@ -242,8 +240,7 @@ function commitLifeCycles( committedExpirationTime: ExpirationTime, ): void { switch (finishedWork.tag) { - case ClassComponent: - case ClassComponentLazy: { + case ClassComponent: { const instance = finishedWork.stateNode; if (finishedWork.effectTag & Update) { if (current === null) { @@ -289,7 +286,6 @@ function commitLifeCycles( instance = getPublicInstance(finishedWork.child.stateNode); break; case ClassComponent: - case ClassComponentLazy: instance = finishedWork.child.stateNode; break; } @@ -496,8 +492,7 @@ function commitUnmount(current: Fiber): void { onCommitUnmount(current); switch (current.tag) { - case ClassComponent: - case ClassComponentLazy: { + case ClassComponent: { safelyDetachRef(current); const instance = current.stateNode; if (typeof instance.componentWillUnmount === 'function') { @@ -590,8 +585,7 @@ function commitContainer(finishedWork: Fiber) { } switch (finishedWork.tag) { - case ClassComponent: - case ClassComponentLazy: { + case ClassComponent: { return; } case HostComponent: { @@ -876,8 +870,7 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void { } switch (finishedWork.tag) { - case ClassComponent: - case ClassComponentLazy: { + case ClassComponent: { return; } case HostComponent: { diff --git a/packages/react-reconciler/src/ReactFiberCompleteWork.js b/packages/react-reconciler/src/ReactFiberCompleteWork.js index a5d16facc3831..9b67a6e63fcbd 100644 --- a/packages/react-reconciler/src/ReactFiberCompleteWork.js +++ b/packages/react-reconciler/src/ReactFiberCompleteWork.js @@ -22,9 +22,7 @@ import type {SuspenseState} from './ReactFiberSuspenseComponent'; import { IndeterminateComponent, FunctionComponent, - FunctionComponentLazy, ClassComponent, - ClassComponentLazy, HostRoot, HostComponent, HostText, @@ -36,9 +34,7 @@ import { Mode, Profiler, SuspenseComponent, - ForwardRefLazy, PureComponent, - PureComponentLazy, } from 'shared/ReactWorkTags'; import {Placement, Ref, Update} from 'shared/ReactSideEffectTags'; import invariant from 'shared/invariant'; @@ -541,7 +537,6 @@ function completeWork( case IndeterminateComponent: break; case FunctionComponent: - case FunctionComponentLazy: break; case ClassComponent: { const Component = workInProgress.type; @@ -550,13 +545,6 @@ function completeWork( } break; } - case ClassComponentLazy: { - const Component = workInProgress.type; - if (isLegacyContextProvider(Component)) { - popLegacyContext(workInProgress); - } - break; - } case HostRoot: { popHostContainer(workInProgress); popTopLevelLegacyContextObject(workInProgress); @@ -693,8 +681,6 @@ function completeWork( break; } case ForwardRef: - case ForwardRefLazy: - break; case SuspenseComponent: { const nextState = workInProgress.memoizedState; const prevState = current !== null ? current.memoizedState : null; @@ -724,7 +710,6 @@ function completeWork( case ContextConsumer: break; case PureComponent: - case PureComponentLazy: break; default: invariant( diff --git a/packages/react-reconciler/src/ReactFiberContext.js b/packages/react-reconciler/src/ReactFiberContext.js index da8accc11c954..e5f63a31f241a 100644 --- a/packages/react-reconciler/src/ReactFiberContext.js +++ b/packages/react-reconciler/src/ReactFiberContext.js @@ -11,11 +11,7 @@ import type {Fiber} from './ReactFiber'; import type {StackCursor} from './ReactFiberStack'; import {isFiberMounted} from 'react-reconciler/reflection'; -import { - ClassComponent, - HostRoot, - ClassComponentLazy, -} from 'shared/ReactWorkTags'; +import {ClassComponent, HostRoot} from 'shared/ReactWorkTags'; import getComponentName from 'shared/getComponentName'; import invariant from 'shared/invariant'; import warningWithoutStack from 'shared/warningWithoutStack'; @@ -278,8 +274,7 @@ function findCurrentUnmaskedContext(fiber: Fiber): Object { // Currently this is only used with renderSubtreeIntoContainer; not sure if it // makes sense elsewhere invariant( - isFiberMounted(fiber) && - (fiber.tag === ClassComponent || fiber.tag === ClassComponentLazy), + isFiberMounted(fiber) && fiber.tag === ClassComponent, 'Expected subtree parent to be a mounted class component. ' + 'This error is likely caused by a bug in React. Please file an issue.', ); @@ -296,13 +291,6 @@ function findCurrentUnmaskedContext(fiber: Fiber): Object { } break; } - case ClassComponentLazy: { - const Component = node.type; - if (isContextProvider(Component)) { - return node.stateNode.__reactInternalMemoizedMergedChildContext; - } - break; - } } node = node.return; } while (node !== null); diff --git a/packages/react-reconciler/src/ReactFiberNewContext.js b/packages/react-reconciler/src/ReactFiberNewContext.js index fd4a739bfcf39..44a6f73cac6c9 100644 --- a/packages/react-reconciler/src/ReactFiberNewContext.js +++ b/packages/react-reconciler/src/ReactFiberNewContext.js @@ -23,11 +23,7 @@ import {isPrimaryRenderer} from './ReactFiberHostConfig'; import {createCursor, push, pop} from './ReactFiberStack'; import maxSigned31BitInt from './maxSigned31BitInt'; import {NoWork} from './ReactFiberExpirationTime'; -import { - ContextProvider, - ClassComponent, - ClassComponentLazy, -} from 'shared/ReactWorkTags'; +import {ContextProvider, ClassComponent} from 'shared/ReactWorkTags'; import invariant from 'shared/invariant'; import warning from 'shared/warning'; @@ -163,10 +159,7 @@ export function propagateContextChange( ) { // Match! Schedule an update on this fiber. - if ( - fiber.tag === ClassComponent || - fiber.tag === ClassComponentLazy - ) { + if (fiber.tag === ClassComponent) { // Schedule a force update on the work-in-progress. const update = createUpdate(renderExpirationTime); update.tag = ForceUpdate; diff --git a/packages/react-reconciler/src/ReactFiberReconciler.js b/packages/react-reconciler/src/ReactFiberReconciler.js index 3c47f7da968ad..d594267a1094e 100644 --- a/packages/react-reconciler/src/ReactFiberReconciler.js +++ b/packages/react-reconciler/src/ReactFiberReconciler.js @@ -23,11 +23,7 @@ import { findCurrentHostFiberWithNoPortals, } from 'react-reconciler/reflection'; import * as ReactInstanceMap from 'shared/ReactInstanceMap'; -import { - HostComponent, - ClassComponent, - ClassComponentLazy, -} from 'shared/ReactWorkTags'; +import {HostComponent, ClassComponent} from 'shared/ReactWorkTags'; import getComponentName from 'shared/getComponentName'; import invariant from 'shared/invariant'; import warningWithoutStack from 'shared/warningWithoutStack'; @@ -105,11 +101,6 @@ function getContextForSubtree( if (isLegacyContextProvider(Component)) { return processChildContext(fiber, Component, parentContext); } - } else if (fiber.tag === ClassComponentLazy) { - const Component = fiber.type; - if (isLegacyContextProvider(Component)) { - return processChildContext(fiber, Component, parentContext); - } } return parentContext; diff --git a/packages/react-reconciler/src/ReactFiberScheduler.js b/packages/react-reconciler/src/ReactFiberScheduler.js index beaf5daf21404..6d80e9ce03fdb 100644 --- a/packages/react-reconciler/src/ReactFiberScheduler.js +++ b/packages/react-reconciler/src/ReactFiberScheduler.js @@ -38,7 +38,6 @@ import { import { HostRoot, ClassComponent, - ClassComponentLazy, HostComponent, ContextProvider, HostPortal, @@ -315,13 +314,6 @@ if (__DEV__ && replayFailedUnitOfWorkWithInvokeGuardedCallback) { } break; } - case ClassComponentLazy: { - const Component = failedUnitOfWork.type; - if (isLegacyContextProvider(Component)) { - popLegacyContext(failedUnitOfWork); - } - break; - } case HostPortal: popHostContainer(failedUnitOfWork); break; @@ -1435,7 +1427,6 @@ function dispatch( while (fiber !== null) { switch (fiber.tag) { case ClassComponent: - case ClassComponentLazy: const ctor = fiber.type; const instance = fiber.stateNode; if ( @@ -1632,7 +1623,7 @@ function scheduleWorkToRoot(fiber: Fiber, expirationTime): FiberRoot | null { recordScheduleUpdate(); if (__DEV__) { - if (fiber.tag === ClassComponent || fiber.tag === ClassComponentLazy) { + if (fiber.tag === ClassComponent) { const instance = fiber.stateNode; warnAboutInvalidUpdates(instance); } @@ -1689,10 +1680,7 @@ function scheduleWorkToRoot(fiber: Fiber, expirationTime): FiberRoot | null { } if (root === null) { - if ( - __DEV__ && - (fiber.tag === ClassComponent || fiber.tag === ClassComponentLazy) - ) { + if (__DEV__ && fiber.tag === ClassComponent) { warnAboutUpdateOnUnmounted(fiber); } return null; diff --git a/packages/react-reconciler/src/ReactFiberTreeReflection.js b/packages/react-reconciler/src/ReactFiberTreeReflection.js index a2cf418b5ed11..a5ace9487fce0 100644 --- a/packages/react-reconciler/src/ReactFiberTreeReflection.js +++ b/packages/react-reconciler/src/ReactFiberTreeReflection.js @@ -17,7 +17,6 @@ import ReactSharedInternals from 'shared/ReactSharedInternals'; import getComponentName from 'shared/getComponentName'; import { ClassComponent, - ClassComponentLazy, HostComponent, HostRoot, HostPortal, @@ -67,10 +66,7 @@ export function isFiberMounted(fiber: Fiber): boolean { export function isMounted(component: React$Component): boolean { if (__DEV__) { const owner = (ReactCurrentOwner.current: any); - if ( - owner !== null && - (owner.tag === ClassComponent || owner.tag === ClassComponentLazy) - ) { + if (owner !== null && owner.tag === ClassComponent) { const ownerFiber: Fiber = owner; const instance = ownerFiber.stateNode; warningWithoutStack( diff --git a/packages/react-reconciler/src/ReactFiberUnwindWork.js b/packages/react-reconciler/src/ReactFiberUnwindWork.js index a39d3d6a9e92d..872fb1cd89dd7 100644 --- a/packages/react-reconciler/src/ReactFiberUnwindWork.js +++ b/packages/react-reconciler/src/ReactFiberUnwindWork.js @@ -19,7 +19,6 @@ import getComponentName from 'shared/getComponentName'; import warningWithoutStack from 'shared/warningWithoutStack'; import { ClassComponent, - ClassComponentLazy, HostRoot, HostComponent, HostPortal, @@ -248,10 +247,7 @@ function throwException( ); sourceFiber.effectTag &= ~Incomplete; - if ( - sourceFiber.tag === ClassComponent || - sourceFiber.tag === ClassComponentLazy - ) { + if (sourceFiber.tag === ClassComponent) { // We're going to commit this fiber even though it didn't // complete. But we shouldn't call any lifecycle methods or // callbacks. Remove all lifecycle effect tags. @@ -341,7 +337,6 @@ function throwException( return; } case ClassComponent: - case ClassComponentLazy: // Capture and retry const errorInfo = value; const ctor = workInProgress.type; @@ -389,18 +384,6 @@ function unwindWork( } return null; } - case ClassComponentLazy: { - const Component = workInProgress.type._reactResult; - if (isLegacyContextProvider(Component)) { - popLegacyContext(workInProgress); - } - const effectTag = workInProgress.effectTag; - if (effectTag & ShouldCapture) { - workInProgress.effectTag = (effectTag & ~ShouldCapture) | DidCapture; - return workInProgress; - } - return null; - } case HostRoot: { popHostContainer(workInProgress); popTopLevelLegacyContextObject(workInProgress); @@ -471,14 +454,6 @@ function unwindInterruptedWork(interruptedWork: Fiber) { } break; } - case ClassComponentLazy: { - const childContextTypes = - interruptedWork.type._reactResult.childContextTypes; - if (childContextTypes !== null && childContextTypes !== undefined) { - popLegacyContext(interruptedWork); - } - break; - } case HostRoot: { popHostContainer(interruptedWork); popTopLevelLegacyContextObject(interruptedWork); diff --git a/packages/react-reconciler/src/ReactUpdateQueue.js b/packages/react-reconciler/src/ReactUpdateQueue.js index 2e4a97f3ae40f..79660bd45b306 100644 --- a/packages/react-reconciler/src/ReactUpdateQueue.js +++ b/packages/react-reconciler/src/ReactUpdateQueue.js @@ -89,7 +89,7 @@ import type {ExpirationTime} from './ReactFiberExpirationTime'; import {NoWork} from './ReactFiberExpirationTime'; import {Callback, ShouldCapture, DidCapture} from 'shared/ReactSideEffectTags'; -import {ClassComponent, ClassComponentLazy} from 'shared/ReactWorkTags'; +import {ClassComponent} from 'shared/ReactWorkTags'; import { debugRenderPhaseSideEffects, @@ -271,7 +271,7 @@ export function enqueueUpdate(fiber: Fiber, update: Update) { if (__DEV__) { if ( - (fiber.tag === ClassComponent || fiber.tag === ClassComponentLazy) && + fiber.tag === ClassComponent && (currentlyProcessingQueue === queue1 || (queue2 !== null && currentlyProcessingQueue === queue2)) && !didWarnUpdateInsideUpdate diff --git a/packages/react-test-renderer/src/ReactTestRenderer.js b/packages/react-test-renderer/src/ReactTestRenderer.js index 440251a69949e..fe4398eee692d 100644 --- a/packages/react-test-renderer/src/ReactTestRenderer.js +++ b/packages/react-test-renderer/src/ReactTestRenderer.js @@ -17,9 +17,7 @@ import {findCurrentFiberUsingSlowPath} from 'react-reconciler/reflection'; import { Fragment, FunctionComponent, - FunctionComponentLazy, ClassComponent, - ClassComponentLazy, HostComponent, HostPortal, HostText, @@ -29,9 +27,7 @@ import { Mode, ForwardRef, Profiler, - ForwardRefLazy, PureComponent, - PureComponentLazy, } from 'shared/ReactWorkTags'; import invariant from 'shared/invariant'; import ReactVersion from 'shared/ReactVersion'; @@ -169,17 +165,6 @@ function toTree(node: ?Fiber) { instance: node.stateNode, rendered: childrenToTree(node.child), }; - case ClassComponentLazy: { - const thenable = node.type; - const type = thenable._reactResult; - return { - nodeType: 'component', - type, - props: {...node.memoizedProps}, - instance: node.stateNode, - rendered: childrenToTree(node.child), - }; - } case FunctionComponent: return { nodeType: 'component', @@ -188,17 +173,6 @@ function toTree(node: ?Fiber) { instance: null, rendered: childrenToTree(node.child), }; - case FunctionComponentLazy: { - const thenable = node.type; - const type = thenable._reactResult; - return { - nodeType: 'component', - type: type, - props: {...node.memoizedProps}, - instance: node.stateNode, - rendered: childrenToTree(node.child), - }; - } case HostComponent: { return { nodeType: 'host', @@ -216,9 +190,7 @@ function toTree(node: ?Fiber) { case Mode: case Profiler: case ForwardRef: - case ForwardRefLazy: case PureComponent: - case PureComponentLazy: return childrenToTree(node.child); default: invariant( @@ -231,14 +203,10 @@ function toTree(node: ?Fiber) { const validWrapperTypes = new Set([ FunctionComponent, - FunctionComponentLazy, ClassComponent, - ClassComponentLazy, HostComponent, ForwardRef, - ForwardRefLazy, PureComponent, - PureComponentLazy, // Normally skipped, but used when there's more than one root child. HostRoot, ]); diff --git a/packages/shared/ReactWorkTags.js b/packages/shared/ReactWorkTags.js index 33e4673cfc3eb..04e0debfbc6f8 100644 --- a/packages/shared/ReactWorkTags.js +++ b/packages/shared/ReactWorkTags.js @@ -29,9 +29,7 @@ export type WorkTag = | 18; export const FunctionComponent = 0; -export const FunctionComponentLazy = 1; export const ClassComponent = 2; -export const ClassComponentLazy = 3; export const IndeterminateComponent = 4; // Before we know whether it is function or class export const HostRoot = 5; // Root of a host tree. Could be nested inside another node. export const HostPortal = 6; // A subtree. Could be an entry point to a different renderer. @@ -42,8 +40,6 @@ export const Mode = 10; export const ContextConsumer = 11; export const ContextProvider = 12; export const ForwardRef = 13; -export const ForwardRefLazy = 14; export const Profiler = 15; export const SuspenseComponent = 16; export const PureComponent = 17; -export const PureComponentLazy = 18; From e6b9e26a6634a30adbe3d838151096cec4fd1203 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Fri, 19 Oct 2018 19:51:02 -0700 Subject: [PATCH 5/7] Collapse work tag numbering --- packages/shared/ReactWorkTags.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/shared/ReactWorkTags.js b/packages/shared/ReactWorkTags.js index 04e0debfbc6f8..49b57371632e8 100644 --- a/packages/shared/ReactWorkTags.js +++ b/packages/shared/ReactWorkTags.js @@ -29,17 +29,17 @@ export type WorkTag = | 18; export const FunctionComponent = 0; -export const ClassComponent = 2; -export const IndeterminateComponent = 4; // Before we know whether it is function or class -export const HostRoot = 5; // Root of a host tree. Could be nested inside another node. -export const HostPortal = 6; // A subtree. Could be an entry point to a different renderer. -export const HostComponent = 7; -export const HostText = 8; -export const Fragment = 9; -export const Mode = 10; -export const ContextConsumer = 11; -export const ContextProvider = 12; -export const ForwardRef = 13; -export const Profiler = 15; -export const SuspenseComponent = 16; -export const PureComponent = 17; +export const ClassComponent = 1; +export const IndeterminateComponent = 2; // Before we know whether it is function or class +export const HostRoot = 3; // Root of a host tree. Could be nested inside another node. +export const HostPortal = 4; // A subtree. Could be an entry point to a different renderer. +export const HostComponent = 5; +export const HostText = 6; +export const Fragment = 7; +export const Mode = 8; +export const ContextConsumer = 9; +export const ContextProvider = 10; +export const ForwardRef = 11; +export const Profiler = 12; +export const SuspenseComponent = 13; +export const PureComponent = 14; From 6a70389d516464ab8ac98f8c26dc5ac8388a15c5 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Fri, 19 Oct 2018 20:01:35 -0700 Subject: [PATCH 6/7] Split IndeterminateComponent out from Lazy This way we don't have to check the type in a hacky way in the indeterminate path. Also, lets us deal with lazy that resolves to indeterminate and such. --- .../react-reconciler/src/ReactCurrentFiber.js | 2 + packages/react-reconciler/src/ReactFiber.js | 3 +- .../src/ReactFiberBeginWork.js | 174 ++++++++++-------- .../src/ReactFiberCompleteWork.js | 3 + packages/shared/ReactWorkTags.js | 1 + 5 files changed, 104 insertions(+), 79 deletions(-) diff --git a/packages/react-reconciler/src/ReactCurrentFiber.js b/packages/react-reconciler/src/ReactCurrentFiber.js index ea52ec292e12b..661c46fffe83b 100644 --- a/packages/react-reconciler/src/ReactCurrentFiber.js +++ b/packages/react-reconciler/src/ReactCurrentFiber.js @@ -14,6 +14,7 @@ import { ClassComponent, HostComponent, Mode, + LazyComponent, } from 'shared/ReactWorkTags'; import describeComponentFrame from 'shared/describeComponentFrame'; import getComponentName from 'shared/getComponentName'; @@ -27,6 +28,7 @@ type LifeCyclePhase = 'render' | 'getChildContext'; function describeFiber(fiber: Fiber): string { switch (fiber.tag) { case IndeterminateComponent: + case LazyComponent: case FunctionComponent: case ClassComponent: case HostComponent: diff --git a/packages/react-reconciler/src/ReactFiber.js b/packages/react-reconciler/src/ReactFiber.js index 4876ee44cce4a..78f25688009d3 100644 --- a/packages/react-reconciler/src/ReactFiber.js +++ b/packages/react-reconciler/src/ReactFiber.js @@ -36,6 +36,7 @@ import { SuspenseComponent, FunctionComponent, PureComponent, + LazyComponent, } from 'shared/ReactWorkTags'; import getComponentName from 'shared/getComponentName'; @@ -473,7 +474,7 @@ function createFiberFromElementWithoutDebugInfo( fiberTag = PureComponent; break getTag; case REACT_LAZY_TYPE: - fiberTag = IndeterminateComponent; + fiberTag = LazyComponent; resolvedType = null; break getTag; } diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js index 6dbca81603d1e..4f7df37fb1719 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.js @@ -31,6 +31,7 @@ import { Profiler, SuspenseComponent, PureComponent, + LazyComponent, } from 'shared/ReactWorkTags'; import { NoEffect, @@ -105,7 +106,6 @@ import { createFiberFromFragment, createWorkInProgress, } from './ReactFiber'; -import {REACT_LAZY_TYPE} from 'shared/ReactSymbols'; const ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner; @@ -700,7 +700,7 @@ function resolveDefaultProps(Component, baseProps) { return baseProps; } -function mountIndeterminateComponent( +function mountLazyComponent( _current, workInProgress, elementType, @@ -719,85 +719,94 @@ function mountIndeterminateComponent( } const props = workInProgress.pendingProps; - let Component; - if ( - typeof elementType === 'object' && - elementType !== null && - elementType.$$typeof === REACT_LAZY_TYPE - ) { - // We can't start a User Timing measurement with correct label yet. - // Cancel and resume right after we know the tag. - cancelWorkTimer(workInProgress); - Component = readLazyComponentType(elementType); - // Store the unwrapped component in the type. - workInProgress.type = Component; - const resolvedTag = (workInProgress.tag = resolveLazyComponentTag( - workInProgress, - Component, - )); - startWorkTimer(workInProgress); - const resolvedProps = resolveDefaultProps(Component, props); - let child; - switch (resolvedTag) { - case FunctionComponent: { - child = updateFunctionComponent( - null, - workInProgress, - Component, - resolvedProps, - renderExpirationTime, - ); - break; - } - case ClassComponent: { - child = updateClassComponent( - null, - workInProgress, - Component, - resolvedProps, - renderExpirationTime, - ); - break; - } - case ForwardRef: { - child = updateForwardRef( - null, - workInProgress, - Component, - resolvedProps, - renderExpirationTime, - ); - break; - } - case PureComponent: { - child = updatePureComponent( - null, - workInProgress, - Component, - resolvedProps, - updateExpirationTime, - renderExpirationTime, - ); - break; - } - default: { - // This message intentionally doesn't metion ForwardRef or PureComponent - // because the fact that it's a separate type of work is an - // implementation detail. - invariant( - false, - 'Element type is invalid. Received a promise that resolves to: %s. ' + - 'Promise elements must resolve to a class or function.', - Component, - ); - } + // We can't start a User Timing measurement with correct label yet. + // Cancel and resume right after we know the tag. + cancelWorkTimer(workInProgress); + let Component = readLazyComponentType(elementType); + // Store the unwrapped component in the type. + workInProgress.type = Component; + const resolvedTag = (workInProgress.tag = resolveLazyComponentTag( + workInProgress, + Component, + )); + startWorkTimer(workInProgress); + const resolvedProps = resolveDefaultProps(Component, props); + let child; + switch (resolvedTag) { + case FunctionComponent: { + child = updateFunctionComponent( + null, + workInProgress, + Component, + resolvedProps, + renderExpirationTime, + ); + break; } - return child; - } else { - workInProgress.type = elementType; - Component = elementType; + case ClassComponent: { + child = updateClassComponent( + null, + workInProgress, + Component, + resolvedProps, + renderExpirationTime, + ); + break; + } + case ForwardRef: { + child = updateForwardRef( + null, + workInProgress, + Component, + resolvedProps, + renderExpirationTime, + ); + break; + } + case PureComponent: { + child = updatePureComponent( + null, + workInProgress, + Component, + resolvedProps, + updateExpirationTime, + renderExpirationTime, + ); + break; + } + default: { + // This message intentionally doesn't metion ForwardRef or PureComponent + // because the fact that it's a separate type of work is an + // implementation detail. + invariant( + false, + 'Element type is invalid. Received a promise that resolves to: %s. ' + + 'Promise elements must resolve to a class or function.', + Component, + ); + } + } + return child; +} + +function mountIndeterminateComponent( + _current, + workInProgress, + Component, + renderExpirationTime, +) { + if (_current !== null) { + // An indeterminate component only mounts if it suspended inside a non- + // concurrent tree, in an inconsistent state. We want to tree it like + // a new mount, even though an empty version of it already committed. + // Disconnect the alternate pointers. + _current.alternate = null; + workInProgress.alternate = null; + // Since this is conceptually a new fiber, schedule a Placement effect + workInProgress.effectTag |= Placement; } + const props = workInProgress.pendingProps; const unmaskedContext = getUnmaskedContext(workInProgress, Component, false); const context = getMaskedContext(workInProgress, unmaskedContext); @@ -1452,6 +1461,15 @@ function beginWork( case IndeterminateComponent: { const elementType = workInProgress.elementType; return mountIndeterminateComponent( + current, + workInProgress, + elementType, + renderExpirationTime, + ); + } + case LazyComponent: { + const elementType = workInProgress.elementType; + return mountLazyComponent( current, workInProgress, elementType, diff --git a/packages/react-reconciler/src/ReactFiberCompleteWork.js b/packages/react-reconciler/src/ReactFiberCompleteWork.js index 9b67a6e63fcbd..b8270ea1fa0be 100644 --- a/packages/react-reconciler/src/ReactFiberCompleteWork.js +++ b/packages/react-reconciler/src/ReactFiberCompleteWork.js @@ -35,6 +35,7 @@ import { Profiler, SuspenseComponent, PureComponent, + LazyComponent, } from 'shared/ReactWorkTags'; import {Placement, Ref, Update} from 'shared/ReactSideEffectTags'; import invariant from 'shared/invariant'; @@ -536,6 +537,8 @@ function completeWork( switch (workInProgress.tag) { case IndeterminateComponent: break; + case LazyComponent: + break; case FunctionComponent: break; case ClassComponent: { diff --git a/packages/shared/ReactWorkTags.js b/packages/shared/ReactWorkTags.js index 49b57371632e8..be815784f7753 100644 --- a/packages/shared/ReactWorkTags.js +++ b/packages/shared/ReactWorkTags.js @@ -43,3 +43,4 @@ export const ForwardRef = 11; export const Profiler = 12; export const SuspenseComponent = 13; export const PureComponent = 14; +export const LazyComponent = 15; From b2ee27445094fe05f218fe052c48c320f8c1bb65 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Fri, 19 Oct 2018 20:41:09 -0700 Subject: [PATCH 7/7] Missing clean up in rebase --- packages/react-reconciler/src/ReactFiberScheduler.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberScheduler.js b/packages/react-reconciler/src/ReactFiberScheduler.js index 6d80e9ce03fdb..34be16bdb2525 100644 --- a/packages/react-reconciler/src/ReactFiberScheduler.js +++ b/packages/react-reconciler/src/ReactFiberScheduler.js @@ -1600,10 +1600,7 @@ function retrySuspendedRoot( // therefore does not have any pending work. scheduleWorkToRoot(sourceFiber, retryTime); const sourceTag = sourceFiber.tag; - if ( - (sourceTag === ClassComponent || sourceFiber === ClassComponentLazy) && - sourceFiber.stateNode !== null - ) { + if (sourceTag === ClassComponent && sourceFiber.stateNode !== null) { // When we try rendering again, we should not reuse the current fiber, // since it's known to be in an inconsistent state. Use a force updte to // prevent a bail out.