diff --git a/packages/react-dom/src/__tests__/ReactServerRendering-test.js b/packages/react-dom/src/__tests__/ReactServerRendering-test.js
index b920a025eae85..56ee796e569b2 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 a28b41fc12c90..4c3335d062125 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 ab4c8a17a6d96..93e6ffae5daf0 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 ea595f5f538b0..2231dc5ae5b61 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 394b35ae906d8..14085aff5128b 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 280eef0609a14..31c6cbd174d04 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,46 +49,44 @@ describe('ReactBlocks', () => {
};
});
- it.experimental('renders a component with a suspending query', async () => {
- function Query(id) {
+ it.experimental('prints the name of the render function in warnings', () => {
+ function Query(firstName) {
return {
- id: id,
- name: readString('Sebastian'),
+ name: firstName,
};
}
- function Render(props, data) {
- return (
-
- {props.title}: {data.name}
-
- );
+ function User(props, data) {
+ let array = [{data.name}];
+ return {array}
;
}
- let loadUser = block(Query, Render);
-
- function App({User}) {
+ function App({Component}) {
return (
-
+
);
}
- await ReactNoop.act(async () => {
- ReactNoop.render();
- });
+ let loadUser = block(Query, User);
- expect(ReactNoop).toMatchRenderedOutput('Loading...');
-
- await ReactNoop.act(async () => {
- jest.advanceTimersByTime(1000);
- });
-
- expect(ReactNoop).toMatchRenderedOutput(Name: Sebastian);
+ 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('supports a lazy wrapper around a chunk', async () => {
+ it.experimental('renders a component with a suspending query', async () => {
function Query(id) {
return {
id: id,
@@ -112,30 +112,10 @@ describe('ReactBlocks', () => {
);
}
- 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 () => {
- await resolveLazy();
+ ReactNoop.render();
});
- // We're still waiting on the data.
expect(ReactNoop).toMatchRenderedOutput('Loading...');
await ReactNoop.act(async () => {
@@ -145,6 +125,65 @@ describe('ReactBlocks', () => {
expect(ReactNoop).toMatchRenderedOutput(Name: 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}
+
+ );
+ }
+
+ let loadUser = block(Query, Render);
+
+ function App({User}) {
+ return (
+
+
+
+ );
+ }
+
+ 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 resolveLazy();
+
+ 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',
async () => {
diff --git a/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js b/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js
index d4b2055607059..d542173fce30e 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 2b6c93b110fab..901ee1e90cc5c 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 Initializer = (
- payload: Payload,
-) =>
- | [Data, BlockRenderFunction]
- | Thenable<[Data, BlockRenderFunction], mixed>;
-
-export type UninitializedBlockComponent = {
- $$typeof: Symbol | number,
- _status: -1,
- _data: Payload,
- _fn: Initializer,
-};
-
-export type PendingBlockComponent = {
- $$typeof: Symbol | number,
- _status: 0,
- _data: Thenable<[Data, BlockRenderFunction], mixed>,
- _fn: null,
+type Payload, Data> = {
+ query: BlockQueryFunction,
+ args: Args,
+ render: BlockRenderFunction,
};
-export type ResolvedBlockComponent = {
+export type BlockComponent = {
$$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 1de3189c923c6..442ada2ebe830 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 8ed9a35b4ea68..0000000000000
--- 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 8baa0ad217248..0000000000000
--- 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 9817ea21963ee..3aabfaf8a4787 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;
}
}
}