diff --git a/packages/react-dom/src/__tests__/ReactServerRendering-test.js b/packages/react-dom/src/__tests__/ReactServerRendering-test.js index b920a025ea..56ee796e56 100644 --- a/packages/react-dom/src/__tests__/ReactServerRendering-test.js +++ b/packages/react-dom/src/__tests__/ReactServerRendering-test.js @@ -709,7 +709,7 @@ describe('ReactDOMServer', () => { ), ); ReactDOMServer.renderToString(); - }).toThrow('ReactDOMServer does not yet support lazy-loaded components.'); + }).toThrow('ReactDOMServer does not yet support Suspense.'); }); it('throws when suspending on the server', () => { diff --git a/packages/react-dom/src/server/ReactPartialRenderer.js b/packages/react-dom/src/server/ReactPartialRenderer.js index a28b41fc12..4c3335d062 100644 --- a/packages/react-dom/src/server/ReactPartialRenderer.js +++ b/packages/react-dom/src/server/ReactPartialRenderer.js @@ -17,8 +17,6 @@ import invariant from 'shared/invariant'; import getComponentName from 'shared/getComponentName'; import describeComponentFrame from 'shared/describeComponentFrame'; import ReactSharedInternals from 'shared/ReactSharedInternals'; -import {initializeLazyComponentType} from 'shared/ReactLazyComponent'; -import {Resolved, Rejected, Pending} from 'shared/ReactLazyStatusTags'; import { warnAboutDeprecatedLifecycles, disableLegacyContext, @@ -1233,42 +1231,33 @@ class ReactDOMServerRenderer { // eslint-disable-next-line-no-fallthrough case REACT_LAZY_TYPE: { const element: ReactElement = (nextChild: any); - const lazyComponent: LazyComponent = (nextChild: any).type; + const lazyComponent: LazyComponent = (nextChild: any) + .type; // Attempt to initialize lazy component regardless of whether the // suspense server-side renderer is enabled so synchronously // resolved constructors are supported. - initializeLazyComponentType(lazyComponent); - switch (lazyComponent._status) { - case Resolved: { - const nextChildren = [ - React.createElement( - lazyComponent._result, - Object.assign({ref: element.ref}, element.props), - ), - ]; - const frame: Frame = { - type: null, - domNamespace: parentNamespace, - children: nextChildren, - childIndex: 0, - context: context, - footer: '', - }; - if (__DEV__) { - ((frame: any): FrameDev).debugElementStack = []; - } - this.stack.push(frame); - return ''; - } - case Rejected: - throw lazyComponent._result; - case Pending: - default: - invariant( - false, - 'ReactDOMServer does not yet support lazy-loaded components.', - ); + let payload = lazyComponent._payload; + let init = lazyComponent._init; + let result = init(payload); + const nextChildren = [ + React.createElement( + result, + Object.assign({ref: element.ref}, element.props), + ), + ]; + const frame: Frame = { + type: null, + domNamespace: parentNamespace, + children: nextChildren, + childIndex: 0, + context: context, + footer: '', + }; + if (__DEV__) { + ((frame: any): FrameDev).debugElementStack = []; } + this.stack.push(frame); + return ''; } // eslint-disable-next-line-no-fallthrough case REACT_SCOPE_TYPE: { diff --git a/packages/react-reconciler/src/ReactChildFiber.js b/packages/react-reconciler/src/ReactChildFiber.js index ab4c8a17a6..93e6ffae5d 100644 --- a/packages/react-reconciler/src/ReactChildFiber.js +++ b/packages/react-reconciler/src/ReactChildFiber.js @@ -10,6 +10,7 @@ import type {ReactElement} from 'shared/ReactElementType'; import type {ReactPortal} from 'shared/ReactTypes'; import type {BlockComponent} from 'react/src/ReactBlock'; +import type {LazyComponent} from 'react/src/ReactLazy'; import type {Fiber} from './ReactFiber'; import type {ExpirationTime} from './ReactFiberExpirationTime'; @@ -20,6 +21,7 @@ import { REACT_ELEMENT_TYPE, REACT_FRAGMENT_TYPE, REACT_PORTAL_TYPE, + REACT_LAZY_TYPE, REACT_BLOCK_TYPE, } from 'shared/ReactSymbols'; import { @@ -48,7 +50,6 @@ import { } from './ReactCurrentFiber'; import {isCompatibleFamilyForHotReloading} from './ReactFiberHotReloading'; import {StrictMode} from './ReactTypeOfMode'; -import {initializeBlockComponentType} from 'shared/ReactLazyComponent'; let didWarnAboutMaps; let didWarnAboutGenerators; @@ -263,6 +264,22 @@ function warnOnFunctionType() { } } +// We avoid inlining this to avoid potential deopts from using try/catch. +/** @noinline */ +function resolveLazyType( + lazyComponent: LazyComponent, +): LazyComponent | T { + try { + // If we can, let's peek at the resulting type. + let payload = lazyComponent._payload; + let init = lazyComponent._init; + return init(payload); + } catch (x) { + // Leave it in place and let it throw again in the begin phase. + return lazyComponent; + } +} + // This wrapper function exists because I expect to clone the code in each path // to be able to optimize each path individually by branching early. This needs // a compiler or we can do it manually. Helpers that don't need this branching @@ -419,22 +436,22 @@ function ChildReconciler(shouldTrackSideEffects) { existing._debugOwner = element._owner; } return existing; - } else if ( - enableBlocksAPI && - current.tag === Block && - element.type.$$typeof === REACT_BLOCK_TYPE - ) { + } else if (enableBlocksAPI && current.tag === Block) { // The new Block might not be initialized yet. We need to initialize // it in case initializing it turns out it would match. - initializeBlockComponentType(element.type); + let type = element.type; + if (type.$$typeof === REACT_LAZY_TYPE) { + type = resolveLazyType(type); + } if ( - (element.type: BlockComponent)._fn === - (current.type: BlockComponent)._fn + type.$$typeof === REACT_BLOCK_TYPE && + ((type: any): BlockComponent)._render === + (current.type: BlockComponent)._render ) { // Same as above but also update the .type field. const existing = useFiber(current, element.props); existing.return = returnFiber; - existing.type = element.type; + existing.type = type; if (__DEV__) { existing._debugSource = element._source; existing._debugOwner = element._owner; @@ -1188,17 +1205,20 @@ function ChildReconciler(shouldTrackSideEffects) { } case Block: if (enableBlocksAPI) { - if (element.type.$$typeof === REACT_BLOCK_TYPE) { + let type = element.type; + if (type.$$typeof === REACT_LAZY_TYPE) { + type = resolveLazyType(type); + } + if (type.$$typeof === REACT_BLOCK_TYPE) { // The new Block might not be initialized yet. We need to initialize // it in case initializing it turns out it would match. - initializeBlockComponentType(element.type); if ( - (element.type: BlockComponent)._fn === - (child.type: BlockComponent)._fn + ((type: any): BlockComponent)._render === + (child.type: BlockComponent)._render ) { deleteRemainingChildren(returnFiber, child.sibling); const existing = useFiber(child, element.props); - existing.type = element.type; + existing.type = type; existing.return = returnFiber; if (__DEV__) { existing._debugSource = element._source; diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js index ea595f5f53..2231dc5ae5 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.js @@ -9,6 +9,7 @@ import type {ReactProviderType, ReactContext} from 'shared/ReactTypes'; import type {BlockComponent} from 'react/src/ReactBlock'; +import type {LazyComponent as LazyComponentType} from 'react/src/ReactLazy'; import type {Fiber} from './ReactFiber'; import type {FiberRoot} from './ReactFiberRoot'; import type {ExpirationTime} from './ReactFiberExpirationTime'; @@ -73,7 +74,6 @@ import invariant from 'shared/invariant'; import shallowEqual from 'shared/shallowEqual'; import getComponentName from 'shared/getComponentName'; import ReactStrictModeWarnings from './ReactStrictModeWarnings'; -import {refineResolvedLazyComponent} from 'shared/ReactLazyComponent'; import {REACT_LAZY_TYPE, getIteratorFn} from 'shared/ReactSymbols'; import { getCurrentFiberOwnerNameInDevOrNull, @@ -164,11 +164,7 @@ import { resumeMountClassInstance, updateClassInstance, } from './ReactFiberClassComponent'; -import { - readLazyComponentType, - resolveDefaultProps, -} from './ReactFiberLazyComponent'; -import {initializeBlockComponentType} from 'shared/ReactLazyComponent'; +import {resolveDefaultProps} from './ReactFiberLazyComponent'; import { resolveLazyComponentTag, createFiberFromTypeAndProps, @@ -184,7 +180,6 @@ import { renderDidSuspendDelayIfPossible, markUnprocessedUpdateTime, } from './ReactFiberWorkLoop'; -import {Resolved} from 'shared/ReactLazyStatusTags'; const ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner; @@ -492,7 +487,14 @@ function updateSimpleMemoComponent( // We warn when you define propTypes on lazy() // so let's just skip over it to find memo() outer wrapper. // Inner props for memo are validated later. - outerMemoType = refineResolvedLazyComponent(outerMemoType); + const lazyComponent: LazyComponentType = outerMemoType; + let payload = lazyComponent._payload; + let init = lazyComponent._init; + try { + outerMemoType = init(payload); + } catch (x) { + outerMemoType = null; + } } const outerPropTypes = outerMemoType && (outerMemoType: any).propTypes; if (outerPropTypes) { @@ -703,10 +705,10 @@ function updateFunctionComponent( return workInProgress.child; } -function updateBlock( +function updateBlock( current: Fiber | null, workInProgress: Fiber, - block: BlockComponent, + block: BlockComponent, nextProps: any, renderExpirationTime: ExpirationTime, ) { @@ -714,12 +716,7 @@ function updateBlock( // hasn't yet mounted. This happens after the first render suspends. // We'll need to figure out if this is fine or can cause issues. - initializeBlockComponentType(block); - if (block._status !== Resolved) { - throw block._data; - } - - const render = block._fn; + const render = block._render; const data = block._data; // The rest is a fork of updateFunctionComponent @@ -1142,7 +1139,10 @@ function mountLazyComponent( // 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); + let lazyComponent: LazyComponentType = elementType; + let payload = lazyComponent._payload; + let init = lazyComponent._init; + let Component = init(payload); // Store the unwrapped component in the type. workInProgress.type = Component; const resolvedTag = (workInProgress.tag = resolveLazyComponentTag(Component)); diff --git a/packages/react-reconciler/src/ReactFiberLazyComponent.js b/packages/react-reconciler/src/ReactFiberLazyComponent.js index 394b35ae90..14085aff51 100644 --- a/packages/react-reconciler/src/ReactFiberLazyComponent.js +++ b/packages/react-reconciler/src/ReactFiberLazyComponent.js @@ -7,11 +7,6 @@ * @flow */ -import type {LazyComponent} from 'react/src/ReactLazy'; - -import {Resolved} from 'shared/ReactLazyStatusTags'; -import {initializeLazyComponentType} from 'shared/ReactLazyComponent'; - export function resolveDefaultProps(Component: any, baseProps: Object): Object { if (Component && Component.defaultProps) { // Resolve default props. Taken from ReactElement @@ -26,11 +21,3 @@ export function resolveDefaultProps(Component: any, baseProps: Object): Object { } return baseProps; } - -export function readLazyComponentType(lazyComponent: LazyComponent): T { - initializeLazyComponentType(lazyComponent); - if (lazyComponent._status !== Resolved) { - throw lazyComponent._result; - } - return lazyComponent._result; -} diff --git a/packages/react-reconciler/src/__tests__/ReactBlocks-test.js b/packages/react-reconciler/src/__tests__/ReactBlocks-test.js index 280eef0609..31c6cbd174 100644 --- a/packages/react-reconciler/src/__tests__/ReactBlocks-test.js +++ b/packages/react-reconciler/src/__tests__/ReactBlocks-test.js @@ -14,11 +14,13 @@ let useState; let Suspense; let block; let readString; +let Scheduler; describe('ReactBlocks', () => { beforeEach(() => { jest.resetModules(); + Scheduler = require('scheduler'); React = require('react'); ReactNoop = require('react-noop-renderer'); @@ -47,6 +49,43 @@ describe('ReactBlocks', () => { }; }); + it.experimental('prints the name of the render function in warnings', () => { + function Query(firstName) { + return { + name: firstName, + }; + } + + function User(props, data) { + let array = [{data.name}]; + return
{array}
; + } + + function App({Component}) { + return ( + + + + ); + } + + let loadUser = block(Query, User); + + expect(() => { + ReactNoop.act(() => { + ReactNoop.render(); + }); + }).toErrorDev( + 'Warning: Each child in a list should have a unique ' + + '"key" prop.\n\nCheck the render method of `User`. See ' + + 'https://fb.me/react-warning-keys for more information.\n' + + ' in span (at **)\n' + + ' in User (at **)\n' + + ' in Suspense (at **)\n' + + ' in App (at **)', + ); + }); + it.experimental('renders a component with a suspending query', async () => { function Query(id) { return { @@ -86,64 +125,64 @@ describe('ReactBlocks', () => { expect(ReactNoop).toMatchRenderedOutput(Name: Sebastian); }); - it.experimental('supports a lazy wrapper around a chunk', async () => { - function Query(id) { - return { - id: id, - name: readString('Sebastian'), - }; - } + it.experimental( + 'does not support a lazy wrapper around a chunk', + async () => { + function Query(id) { + return { + id: id, + name: readString('Sebastian'), + }; + } - function Render(props, data) { - return ( - - {props.title}: {data.name} - + function Render(props, data) { + return ( + + {props.title}: {data.name} + + ); + } + + let loadUser = block(Query, Render); + + function App({User}) { + return ( + + + + ); + } + + let resolveLazy; + let LazyUser = React.lazy( + () => + new Promise(resolve => { + resolveLazy = function() { + resolve({ + default: loadUser(123), + }); + }; + }), ); - } - let loadUser = block(Query, Render); + await ReactNoop.act(async () => { + ReactNoop.render(); + }); - function App({User}) { - return ( - - - - ); - } + expect(ReactNoop).toMatchRenderedOutput('Loading...'); - let resolveLazy; - let LazyUser = React.lazy( - () => - new Promise(resolve => { - resolveLazy = function() { - resolve({ - default: loadUser(123), - }); - }; - }), - ); - - await ReactNoop.act(async () => { - ReactNoop.render(); - }); - - expect(ReactNoop).toMatchRenderedOutput('Loading...'); - - // Resolve the component. - await ReactNoop.act(async () => { + // Resolve the component. await resolveLazy(); - }); - // We're still waiting on the data. - expect(ReactNoop).toMatchRenderedOutput('Loading...'); - - await ReactNoop.act(async () => { - jest.advanceTimersByTime(1000); - }); - - expect(ReactNoop).toMatchRenderedOutput(Name: Sebastian); - }); + expect(Scheduler).toFlushAndThrow( + 'Element type is invalid. Received a promise that resolves to: [object Object]. ' + + 'Lazy element type must resolve to a class or function.' + + (__DEV__ + ? ' Did you wrap a component in React.lazy() more than once?' + : ''), + ); + }, + ); it.experimental( 'can receive updated data for the same component', diff --git a/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js b/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js index d4b2055607..d542173fce 100644 --- a/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js @@ -879,7 +879,13 @@ describe('ReactLazy', () => { }, ); - expect(Scheduler).toFlushAndYield(['Started loading', 'Loading...']); + if (__DEV__) { + // Getting the name for the warning cause the loading to start early. + expect(Scheduler).toHaveYielded(['Started loading']); + expect(Scheduler).toFlushAndYield(['Loading...']); + } else { + expect(Scheduler).toFlushAndYield(['Started loading', 'Loading...']); + } expect(root).not.toMatchRenderedOutput(
AB
); await Promise.resolve(); diff --git a/packages/react/src/ReactBlock.js b/packages/react/src/ReactBlock.js index 2b6c93b110..901ee1e90c 100644 --- a/packages/react/src/ReactBlock.js +++ b/packages/react/src/ReactBlock.js @@ -7,7 +7,10 @@ * @flow */ +import type {LazyComponent} from './ReactLazy'; + import { + REACT_LAZY_TYPE, REACT_BLOCK_TYPE, REACT_MEMO_TYPE, REACT_FORWARD_REF_TYPE, @@ -19,55 +22,33 @@ type BlockRenderFunction = ( data: Data, ) => React$Node; -type Thenable = { - then(resolve: (T) => mixed, reject: (mixed) => mixed): R, +type Payload, Data> = { + query: BlockQueryFunction, + args: Args, + render: BlockRenderFunction, }; -type Initializer = ( - payload: Payload, -) => - | [Data, BlockRenderFunction] - | Thenable<[Data, BlockRenderFunction], mixed>; - -export type UninitializedBlockComponent = { +export type BlockComponent = { $$typeof: Symbol | number, - _status: -1, - _data: Payload, - _fn: Initializer, -}; - -export type PendingBlockComponent = { - $$typeof: Symbol | number, - _status: 0, - _data: Thenable<[Data, BlockRenderFunction], mixed>, - _fn: null, -}; - -export type ResolvedBlockComponent = { - $$typeof: Symbol | number, - _status: 1, _data: Data, - _fn: BlockRenderFunction, + _render: BlockRenderFunction, }; -export type RejectedBlockComponent = { - $$typeof: Symbol | number, - _status: 2, - _data: mixed, - _fn: null, -}; - -export type BlockComponent = - | UninitializedBlockComponent - | PendingBlockComponent - | ResolvedBlockComponent - | RejectedBlockComponent; - opaque type Block: React$AbstractComponent< Props, null, > = React$AbstractComponent; +function lazyInitializer, Data>( + payload: Payload, +): BlockComponent { + return { + $$typeof: REACT_BLOCK_TYPE, + _data: payload.query.apply(null, payload.args), + _render: payload.render, + }; +} + export function block, Props, Data>( query: BlockQueryFunction, render: BlockRenderFunction, @@ -115,19 +96,26 @@ export function block, Props, Data>( ); } } - function initializer(args) { - let data = query.apply(null, args); - return [data, render]; - } + return function(): Block { let args: Args = arguments; - let blockComponent: UninitializedBlockComponent = { - $$typeof: REACT_BLOCK_TYPE, - _status: -1, - _data: args, - _fn: initializer, + + let payload: Payload = { + query: query, + args: args, + render: render, }; + + let lazyType: LazyComponent< + BlockComponent, + Payload, + > = { + $$typeof: REACT_LAZY_TYPE, + _payload: payload, + _init: lazyInitializer, + }; + // $FlowFixMe - return blockComponent; + return lazyType; }; } diff --git a/packages/react/src/ReactLazy.js b/packages/react/src/ReactLazy.js index 1de3189c92..442ada2ebe 100644 --- a/packages/react/src/ReactLazy.js +++ b/packages/react/src/ReactLazy.js @@ -13,46 +13,105 @@ type Thenable = { then(resolve: (T) => mixed, reject: (mixed) => mixed): R, }; -export type UninitializedLazyComponent = { - $$typeof: Symbol | number, +const Uninitialized = -1; +const Pending = 0; +const Resolved = 1; +const Rejected = 2; + +type UninitializedPayload = { _status: -1, - _result: () => Thenable<{default: T, ...} | T, mixed>, + _result: () => Thenable<{default: T, ...}, mixed>, }; -export type PendingLazyComponent = { - $$typeof: Symbol | number, +type PendingPayload = { _status: 0, - _result: Thenable<{default: T, ...} | T, mixed>, + _result: Thenable<{default: T, ...}, mixed>, }; -export type ResolvedLazyComponent = { - $$typeof: Symbol | number, +type ResolvedPayload = { _status: 1, _result: T, }; -export type RejectedLazyComponent = { - $$typeof: Symbol | number, +type RejectedPayload = { _status: 2, _result: mixed, }; -export type LazyComponent = - | UninitializedLazyComponent - | PendingLazyComponent - | ResolvedLazyComponent - | RejectedLazyComponent; +type Payload = + | UninitializedPayload + | PendingPayload + | ResolvedPayload + | RejectedPayload; + +export type LazyComponent = { + $$typeof: Symbol | number, + _payload: P, + _init: (payload: P) => T, +}; + +function lazyInitializer(payload: Payload): T { + if (payload._status === Uninitialized) { + const ctor = payload._result; + const thenable = ctor(); + // Transition to the next state. + const pending: PendingPayload = (payload: any); + pending._status = Pending; + pending._result = thenable; + thenable.then( + moduleObject => { + if (payload._status === Pending) { + const defaultExport = moduleObject.default; + if (__DEV__) { + if (defaultExport === undefined) { + console.error( + 'lazy: Expected the result of a dynamic import() call. ' + + 'Instead received: %s\n\nYour code should look like: \n ' + + // Break up imports to avoid accidentally parsing them as dependencies. + 'const MyComponent = lazy(() => imp' + + "ort('./MyComponent'))", + moduleObject, + ); + } + } + // Transition to the next state. + const resolved: ResolvedPayload = (payload: any); + resolved._status = Resolved; + resolved._result = defaultExport; + } + }, + error => { + if (payload._status === Pending) { + // Transition to the next state. + const rejected: RejectedPayload = (payload: any); + rejected._status = Rejected; + rejected._result = error; + } + }, + ); + } + if (payload._status === Resolved) { + return payload._result; + } else { + throw payload._result; + } +} export function lazy( - ctor: () => Thenable<{default: T, ...} | T, mixed>, -): LazyComponent { - let lazyType: LazyComponent = { - $$typeof: REACT_LAZY_TYPE, - // React uses these fields to store the result. + ctor: () => Thenable<{default: T, ...}, mixed>, +): LazyComponent> { + let payload: Payload = { + // We use these fields to store the result. _status: -1, _result: ctor, }; + let lazyType: LazyComponent> = { + $$typeof: REACT_LAZY_TYPE, + _payload: payload, + _init: lazyInitializer, + }; + if (__DEV__) { // In production, this would just set it on the object. let defaultProps; diff --git a/packages/shared/ReactLazyComponent.js b/packages/shared/ReactLazyComponent.js deleted file mode 100644 index 8ed9a35b4e..0000000000 --- a/packages/shared/ReactLazyComponent.js +++ /dev/null @@ -1,126 +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 { - PendingLazyComponent, - ResolvedLazyComponent, - RejectedLazyComponent, - LazyComponent, -} from 'react/src/ReactLazy'; - -import type { - PendingBlockComponent, - ResolvedBlockComponent, - RejectedBlockComponent, - BlockComponent, -} from 'react/src/ReactBlock'; - -import { - Uninitialized, - Pending, - Resolved, - Rejected, -} from './ReactLazyStatusTags'; - -export function refineResolvedLazyComponent( - lazyComponent: LazyComponent, -): T | null { - return lazyComponent._status === Resolved ? lazyComponent._result : null; -} - -export function initializeLazyComponentType( - lazyComponent: LazyComponent, -): void { - if (lazyComponent._status === Uninitialized) { - const ctor = lazyComponent._result; - const thenable = ctor(); - // Transition to the next state. - const pending: PendingLazyComponent = (lazyComponent: any); - pending._status = Pending; - pending._result = thenable; - thenable.then( - moduleObject => { - if (lazyComponent._status === Pending) { - const defaultExport = moduleObject.default; - if (__DEV__) { - if (defaultExport === undefined) { - console.error( - 'lazy: Expected the result of a dynamic import() call. ' + - 'Instead received: %s\n\nYour code should look like: \n ' + - // Break up imports to avoid accidentally parsing them as dependencies. - 'const MyComponent = lazy(() => imp' + - "ort('./MyComponent'))", - moduleObject, - ); - } - } - // Transition to the next state. - const resolved: ResolvedLazyComponent = (lazyComponent: any); - resolved._status = Resolved; - resolved._result = defaultExport; - } - }, - error => { - if (lazyComponent._status === Pending) { - // Transition to the next state. - const rejected: RejectedLazyComponent = (lazyComponent: any); - rejected._status = Rejected; - rejected._result = error; - } - }, - ); - } -} - -export function initializeBlockComponentType( - blockComponent: BlockComponent, -): void { - if (blockComponent._status === Uninitialized) { - const thenableOrTuple = blockComponent._fn(blockComponent._data); - if (typeof thenableOrTuple.then !== 'function') { - let tuple: [any, any] = (thenableOrTuple: any); - const resolved: ResolvedBlockComponent< - Props, - Data, - > = (blockComponent: any); - resolved._status = Resolved; - resolved._data = tuple[0]; - resolved._fn = tuple[1]; - return; - } - const thenable = (thenableOrTuple: any); - // Transition to the next state. - const pending: PendingBlockComponent = (blockComponent: any); - pending._status = Pending; - pending._data = thenable; - pending._fn = null; - thenable.then( - (tuple: [any, any]) => { - if (blockComponent._status === Pending) { - // Transition to the next state. - const resolved: ResolvedBlockComponent< - Props, - Data, - > = (blockComponent: any); - resolved._status = Resolved; - resolved._data = tuple[0]; - resolved._fn = tuple[1]; - } - }, - error => { - if (blockComponent._status === Pending) { - // Transition to the next state. - const rejected: RejectedBlockComponent = (blockComponent: any); - rejected._status = Rejected; - rejected._data = error; - } - }, - ); - } -} diff --git a/packages/shared/ReactLazyStatusTags.js b/packages/shared/ReactLazyStatusTags.js deleted file mode 100644 index 8baa0ad217..0000000000 --- a/packages/shared/ReactLazyStatusTags.js +++ /dev/null @@ -1,14 +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 - */ - -// TODO: Move this to "react" once we can import from externals. -export const Uninitialized = -1; -export const Pending = 0; -export const Resolved = 1; -export const Rejected = 2; diff --git a/packages/shared/getComponentName.js b/packages/shared/getComponentName.js index 9817ea2196..3aabfaf8a4 100644 --- a/packages/shared/getComponentName.js +++ b/packages/shared/getComponentName.js @@ -23,7 +23,6 @@ import { REACT_LAZY_TYPE, REACT_BLOCK_TYPE, } from 'shared/ReactSymbols'; -import {refineResolvedLazyComponent} from 'shared/ReactLazyComponent'; import type {ReactContext, ReactProviderType} from 'shared/ReactTypes'; function getWrappedName( @@ -88,14 +87,16 @@ function getComponentName(type: mixed): string | null { case REACT_MEMO_TYPE: return getComponentName(type.type); case REACT_BLOCK_TYPE: - return getComponentName(type.render); + return getComponentName(type._render); case REACT_LAZY_TYPE: { - const thenable: LazyComponent = (type: any); - const resolvedThenable = refineResolvedLazyComponent(thenable); - if (resolvedThenable) { - return getComponentName(resolvedThenable); + const lazyComponent: LazyComponent = (type: any); + let payload = lazyComponent._payload; + let init = lazyComponent._init; + try { + return getComponentName(init(payload)); + } catch (x) { + return null; } - break; } } }