From fa03206ee4352431198b678c00dca83027e7052d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Wed, 4 Mar 2020 20:52:48 -0800 Subject: [PATCH] Remove _ctor field from Lazy components (#18217) * This type is all wrong and nothing cares because it's all any * Refine Flow types of Lazy Components We can type each condition. * Remove _ctor field from Lazy components This field is not needed because it's only used before we've initialized, and we don't have anything else to store before we've initialized. * Check for _ctor in case it's an older isomorphic that created it We try not to break across minors but it's no guarantee. * Move types and constants from shared to isomorphic The "react" package owns the data structure of the Lazy component. It creates it and decides how any downstream renderer may use it. * Move constants to shared Apparently we can't depend on react/src/ because the whole package is considered "external" as far as rollup is concerned. --- .../src/server/ReactPartialRenderer.js | 10 +-- .../src/ReactFiberLazyComponent.js | 5 +- packages/react/src/ReactLazy.js | 50 +++++++++++++-- packages/shared/ReactLazyComponent.js | 62 +++++++++---------- packages/shared/ReactLazyStatusTags.js | 14 +++++ packages/shared/getComponentName.js | 2 +- 6 files changed, 95 insertions(+), 48 deletions(-) create mode 100644 packages/shared/ReactLazyStatusTags.js diff --git a/packages/react-dom/src/server/ReactPartialRenderer.js b/packages/react-dom/src/server/ReactPartialRenderer.js index e06f1df9bcd88..a28b41fc12c90 100644 --- a/packages/react-dom/src/server/ReactPartialRenderer.js +++ b/packages/react-dom/src/server/ReactPartialRenderer.js @@ -9,7 +9,7 @@ import type {ThreadID} from './ReactThreadIDAllocator'; import type {ReactElement} from 'shared/ReactElementType'; -import type {LazyComponent} from 'shared/ReactLazyComponent'; +import type {LazyComponent} from 'react/src/ReactLazy'; import type {ReactProvider, ReactContext} from 'shared/ReactTypes'; import * as React from 'react'; @@ -17,12 +17,8 @@ import invariant from 'shared/invariant'; import getComponentName from 'shared/getComponentName'; import describeComponentFrame from 'shared/describeComponentFrame'; import ReactSharedInternals from 'shared/ReactSharedInternals'; -import { - Resolved, - Rejected, - Pending, - initializeLazyComponentType, -} from 'shared/ReactLazyComponent'; +import {initializeLazyComponentType} from 'shared/ReactLazyComponent'; +import {Resolved, Rejected, Pending} from 'shared/ReactLazyStatusTags'; import { warnAboutDeprecatedLifecycles, disableLegacyContext, diff --git a/packages/react-reconciler/src/ReactFiberLazyComponent.js b/packages/react-reconciler/src/ReactFiberLazyComponent.js index 290458eb96928..394b35ae906d8 100644 --- a/packages/react-reconciler/src/ReactFiberLazyComponent.js +++ b/packages/react-reconciler/src/ReactFiberLazyComponent.js @@ -7,9 +7,10 @@ * @flow */ -import type {LazyComponent} from 'shared/ReactLazyComponent'; +import type {LazyComponent} from 'react/src/ReactLazy'; -import {Resolved, initializeLazyComponentType} from 'shared/ReactLazyComponent'; +import {Resolved} from 'shared/ReactLazyStatusTags'; +import {initializeLazyComponentType} from 'shared/ReactLazyComponent'; export function resolveDefaultProps(Component: any, baseProps: Object): Object { if (Component && Component.defaultProps) { diff --git a/packages/react/src/ReactLazy.js b/packages/react/src/ReactLazy.js index c804c53741a60..1de3189c923c6 100644 --- a/packages/react/src/ReactLazy.js +++ b/packages/react/src/ReactLazy.js @@ -3,25 +3,61 @@ * * 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 {LazyComponent, Thenable} from 'shared/ReactLazyComponent'; - import {REACT_LAZY_TYPE} from 'shared/ReactSymbols'; -export function lazy(ctor: () => Thenable): LazyComponent { - let lazyType = { +type Thenable = { + then(resolve: (T) => mixed, reject: (mixed) => mixed): R, +}; + +export type UninitializedLazyComponent = { + $$typeof: Symbol | number, + _status: -1, + _result: () => Thenable<{default: T, ...} | T, mixed>, +}; + +export type PendingLazyComponent = { + $$typeof: Symbol | number, + _status: 0, + _result: Thenable<{default: T, ...} | T, mixed>, +}; + +export type ResolvedLazyComponent = { + $$typeof: Symbol | number, + _status: 1, + _result: T, +}; + +export type RejectedLazyComponent = { + $$typeof: Symbol | number, + _status: 2, + _result: mixed, +}; + +export type LazyComponent = + | UninitializedLazyComponent + | PendingLazyComponent + | ResolvedLazyComponent + | RejectedLazyComponent; + +export function lazy( + ctor: () => Thenable<{default: T, ...} | T, mixed>, +): LazyComponent { + let lazyType: LazyComponent = { $$typeof: REACT_LAZY_TYPE, - _ctor: ctor, // React uses these fields to store the result. _status: -1, - _result: null, + _result: ctor, }; if (__DEV__) { // In production, this would just set it on the object. let defaultProps; let propTypes; + // $FlowFixMe Object.defineProperties(lazyType, { defaultProps: { configurable: true, @@ -36,6 +72,7 @@ export function lazy(ctor: () => Thenable): LazyComponent { ); defaultProps = newDefaultProps; // Match production behavior more closely: + // $FlowFixMe Object.defineProperty(lazyType, 'defaultProps', { enumerable: true, }); @@ -54,6 +91,7 @@ export function lazy(ctor: () => Thenable): LazyComponent { ); propTypes = newPropTypes; // Match production behavior more closely: + // $FlowFixMe Object.defineProperty(lazyType, 'propTypes', { enumerable: true, }); diff --git a/packages/shared/ReactLazyComponent.js b/packages/shared/ReactLazyComponent.js index 246ba41e83da5..24b360a1e57a1 100644 --- a/packages/shared/ReactLazyComponent.js +++ b/packages/shared/ReactLazyComponent.js @@ -7,35 +7,23 @@ * @flow */ -export type Thenable = { - then(resolve: (T) => mixed, reject: (mixed) => mixed): R, - ... -}; +import type { + PendingLazyComponent, + ResolvedLazyComponent, + RejectedLazyComponent, + LazyComponent, +} from 'react/src/ReactLazy'; -export type LazyComponent = { - $$typeof: Symbol | number, - _ctor: () => Thenable<{default: T, ...}, mixed>, - _status: 0 | 1 | 2, - _result: any, - ... -}; - -type ResolvedLazyComponent = { - $$typeof: Symbol | number, - _ctor: () => Thenable<{default: T, ...}, mixed>, - _status: 1, - _result: any, - ... -}; - -export const Uninitialized = -1; -export const Pending = 0; -export const Resolved = 1; -export const Rejected = 2; +import { + Uninitialized, + Pending, + Resolved, + Rejected, +} from './ReactLazyStatusTags'; export function refineResolvedLazyComponent( lazyComponent: LazyComponent, -): ResolvedLazyComponent | null { +): T | null { return lazyComponent._status === Resolved ? lazyComponent._result : null; } @@ -43,10 +31,16 @@ export function initializeLazyComponentType( lazyComponent: LazyComponent, ): void { if (lazyComponent._status === Uninitialized) { - lazyComponent._status = Pending; - const ctor = lazyComponent._ctor; + let ctor = lazyComponent._result; + if (!ctor) { + // TODO: Remove this later. THis only exists in case you use an older "react" package. + ctor = ((lazyComponent: any)._ctor: typeof ctor); + } const thenable = ctor(); - lazyComponent._result = thenable; + // Transition to the next state. + const pending: PendingLazyComponent = (lazyComponent: any); + pending._status = Pending; + pending._result = thenable; thenable.then( moduleObject => { if (lazyComponent._status === Pending) { @@ -61,14 +55,18 @@ export function initializeLazyComponentType( ); } } - lazyComponent._status = Resolved; - lazyComponent._result = defaultExport; + // Transition to the next state. + const resolved: ResolvedLazyComponent = (lazyComponent: any); + resolved._status = Resolved; + resolved._result = defaultExport; } }, error => { if (lazyComponent._status === Pending) { - lazyComponent._status = Rejected; - lazyComponent._result = error; + // Transition to the next state. + const rejected: RejectedLazyComponent = (lazyComponent: any); + rejected._status = Rejected; + rejected._result = error; } }, ); diff --git a/packages/shared/ReactLazyStatusTags.js b/packages/shared/ReactLazyStatusTags.js new file mode 100644 index 0000000000000..8baa0ad217248 --- /dev/null +++ b/packages/shared/ReactLazyStatusTags.js @@ -0,0 +1,14 @@ +/** + * 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 9694732ce5d96..9817ea21963ee 100644 --- a/packages/shared/getComponentName.js +++ b/packages/shared/getComponentName.js @@ -7,7 +7,7 @@ * @flow */ -import type {LazyComponent} from 'shared/ReactLazyComponent'; +import type {LazyComponent} from 'react/src/ReactLazy'; import { REACT_CONTEXT_TYPE,