react/packages/react-native-renderer/src/ReactFiberConfigFabric.js

495 lines
13 KiB
JavaScript
Raw Normal View History

/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
Extracted definition and access to public instances to a separate module in Fabric (#26321) ## Summary The current definition of `Instance` in Fabric has 2 fields: - `node`: reference to the native node in the shadow tree. - `canonical`: public instance provided to users via refs + some internal fields needed by Fabric. We're currently using `canonical` not only as the public instance, but also to store internal properties that Fabric needs to access in different parts of the codebase. Those properties are, in fact, available through refs as well, which breaks encapsulation. This PR splits that into 2 separate fields, leaving the definition of instance as: - `node`: reference to the native node in the shadow tree. - `publicInstance`: public instance provided to users via refs. - Rest of internal fields needed by Fabric at the instance level. This also migrates all the current usages of `canonical` to use the right property depending on the use case. To improve encapsulation (and in preparation for the implementation of this [proposal to bring some DOM APIs to public instances in React Native](https://github.com/react-native-community/discussions-and-proposals/pull/607)), this also **moves the creation of and the access to the public instance to separate modules** (`ReactFabricPublicInstance` and `ReactFabricPublicInstanceUtils`). In a following diff, that module will be moved into the `react-native` repository and we'll access it through `ReactNativePrivateInterface`. ## How did you test this change? Existing unit tests. Manually synced the PR in Meta infra and tested in Catalyst + the integration with DevTools. Everything is working normally.
2023-03-13 21:25:42 +08:00
import type {TouchedViewDataAtPoint, ViewConfig} from './ReactNativeTypes';
import {create, diff} from './ReactNativeAttributePayload';
import {dispatchEvent} from './ReactFabricEventEmitter';
import {
DefaultEventPriority,
DiscreteEventPriority,
} from 'react-reconciler/src/ReactEventPriorities';
import {HostText} from 'react-reconciler/src/ReactWorkTags';
// Modules provided by RN:
import {
[react-native] Use path-based imports instead of Haste for the RN renderer (#15604) * [react-native] Use path-based imports instead of Haste for the RN renderer To move React Native to standard path-based imports instead of Haste, the RN renderer that is generated from the code in this repo needs to use path-based imports as well since the generated code is vendored by RN. This commit makes it so the interface between the generated renderers and RN does not rely on Haste and instead uses a private interface explicitly defined by RN. This inverts control of the abstraction so that RN decides the internals to export rather than React deciding what to import. On RN's side, a new module named `react-native/Libraries/ReactPrivate/ReactNativePrivateInterface` explicitly exports the modules used by the renderers in this repo. (There is also a private module for InitializeCore so that we can import it just for the side effects.) On React's side, the various renderer modules access RN internals through the explicit private interface. The Rollup configuration becomes slimmer since the only external package is now `react-native`, and the individual modules are instead listed out in `ReactNativePrivateInterface`. Task description: https://github.com/facebook/react-native/issues/24770 Sister RN PR (needs to land before this one): https://github.com/facebook/react-native/pull/24782 Test Plan: Ran unit tests and Flow in this repo. Generated the renderers and manually copied them over to the RN repo. Ran the RN tests and launched the RNTester app. * Access natively defined "nativeFabricUIManager" instead of importing it Some places in the Fabric renderers access `nativeFabricUIManager` (a natively defined global) instead of importing UIManager. While this is coupling across repos that depends on the timing of events, it is necessary until we have a way to defer top-level imports to run after `nativeFabricUIManager` is defined. So for consistency we use `nativeFabricUIManager` everywhere (see the comment in https://github.com/facebook/react/pull/15604#pullrequestreview-236842223 for more context).
2019-05-23 15:23:54 +08:00
ReactNativeViewConfigRegistry,
deepFreezeAndThrowOnMutationInDev,
createPublicInstance,
createPublicTextInstance,
type PublicInstance as ReactNativePublicInstance,
type PublicTextInstance,
[react-native] Use path-based imports instead of Haste for the RN renderer (#15604) * [react-native] Use path-based imports instead of Haste for the RN renderer To move React Native to standard path-based imports instead of Haste, the RN renderer that is generated from the code in this repo needs to use path-based imports as well since the generated code is vendored by RN. This commit makes it so the interface between the generated renderers and RN does not rely on Haste and instead uses a private interface explicitly defined by RN. This inverts control of the abstraction so that RN decides the internals to export rather than React deciding what to import. On RN's side, a new module named `react-native/Libraries/ReactPrivate/ReactNativePrivateInterface` explicitly exports the modules used by the renderers in this repo. (There is also a private module for InitializeCore so that we can import it just for the side effects.) On React's side, the various renderer modules access RN internals through the explicit private interface. The Rollup configuration becomes slimmer since the only external package is now `react-native`, and the individual modules are instead listed out in `ReactNativePrivateInterface`. Task description: https://github.com/facebook/react-native/issues/24770 Sister RN PR (needs to land before this one): https://github.com/facebook/react-native/pull/24782 Test Plan: Ran unit tests and Flow in this repo. Generated the renderers and manually copied them over to the RN repo. Ran the RN tests and launched the RNTester app. * Access natively defined "nativeFabricUIManager" instead of importing it Some places in the Fabric renderers access `nativeFabricUIManager` (a natively defined global) instead of importing UIManager. While this is coupling across repos that depends on the timing of events, it is necessary until we have a way to defer top-level imports to run after `nativeFabricUIManager` is defined. So for consistency we use `nativeFabricUIManager` everywhere (see the comment in https://github.com/facebook/react/pull/15604#pullrequestreview-236842223 for more context).
2019-05-23 15:23:54 +08:00
} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
const {
createNode,
cloneNode,
cloneNodeWithNewChildren,
cloneNodeWithNewChildrenAndProps,
cloneNodeWithNewProps,
[react-native] Use path-based imports instead of Haste for the RN renderer (#15604) * [react-native] Use path-based imports instead of Haste for the RN renderer To move React Native to standard path-based imports instead of Haste, the RN renderer that is generated from the code in this repo needs to use path-based imports as well since the generated code is vendored by RN. This commit makes it so the interface between the generated renderers and RN does not rely on Haste and instead uses a private interface explicitly defined by RN. This inverts control of the abstraction so that RN decides the internals to export rather than React deciding what to import. On RN's side, a new module named `react-native/Libraries/ReactPrivate/ReactNativePrivateInterface` explicitly exports the modules used by the renderers in this repo. (There is also a private module for InitializeCore so that we can import it just for the side effects.) On React's side, the various renderer modules access RN internals through the explicit private interface. The Rollup configuration becomes slimmer since the only external package is now `react-native`, and the individual modules are instead listed out in `ReactNativePrivateInterface`. Task description: https://github.com/facebook/react-native/issues/24770 Sister RN PR (needs to land before this one): https://github.com/facebook/react-native/pull/24782 Test Plan: Ran unit tests and Flow in this repo. Generated the renderers and manually copied them over to the RN repo. Ran the RN tests and launched the RNTester app. * Access natively defined "nativeFabricUIManager" instead of importing it Some places in the Fabric renderers access `nativeFabricUIManager` (a natively defined global) instead of importing UIManager. While this is coupling across repos that depends on the timing of events, it is necessary until we have a way to defer top-level imports to run after `nativeFabricUIManager` is defined. So for consistency we use `nativeFabricUIManager` everywhere (see the comment in https://github.com/facebook/react/pull/15604#pullrequestreview-236842223 for more context).
2019-05-23 15:23:54 +08:00
createChildSet: createChildNodeSet,
appendChild: appendChildNode,
appendChildToSet: appendChildNodeToSet,
completeRoot,
registerEventHandler,
unstable_DefaultEventPriority: FabricDefaultPriority,
unstable_DiscreteEventPriority: FabricDiscretePriority,
unstable_getCurrentEventPriority: fabricGetCurrentEventPriority,
[react-native] Use path-based imports instead of Haste for the RN renderer (#15604) * [react-native] Use path-based imports instead of Haste for the RN renderer To move React Native to standard path-based imports instead of Haste, the RN renderer that is generated from the code in this repo needs to use path-based imports as well since the generated code is vendored by RN. This commit makes it so the interface between the generated renderers and RN does not rely on Haste and instead uses a private interface explicitly defined by RN. This inverts control of the abstraction so that RN decides the internals to export rather than React deciding what to import. On RN's side, a new module named `react-native/Libraries/ReactPrivate/ReactNativePrivateInterface` explicitly exports the modules used by the renderers in this repo. (There is also a private module for InitializeCore so that we can import it just for the side effects.) On React's side, the various renderer modules access RN internals through the explicit private interface. The Rollup configuration becomes slimmer since the only external package is now `react-native`, and the individual modules are instead listed out in `ReactNativePrivateInterface`. Task description: https://github.com/facebook/react-native/issues/24770 Sister RN PR (needs to land before this one): https://github.com/facebook/react-native/pull/24782 Test Plan: Ran unit tests and Flow in this repo. Generated the renderers and manually copied them over to the RN repo. Ran the RN tests and launched the RNTester app. * Access natively defined "nativeFabricUIManager" instead of importing it Some places in the Fabric renderers access `nativeFabricUIManager` (a natively defined global) instead of importing UIManager. While this is coupling across repos that depends on the timing of events, it is necessary until we have a way to defer top-level imports to run after `nativeFabricUIManager` is defined. So for consistency we use `nativeFabricUIManager` everywhere (see the comment in https://github.com/facebook/react/pull/15604#pullrequestreview-236842223 for more context).
2019-05-23 15:23:54 +08:00
} = nativeFabricUIManager;
Diff properties in the commit phase instead of generating an update payload (#26583) This removes the concept of `prepareUpdate()`, behind a flag. React Native already does everything in the commit phase, but generates a temporary update payload before applying it. React Fabric does it both in the render phase. Now it just moves it to a single host config. For DOM I forked updateProperties into one that does diffing and updating in one pass vs just applying a pre-diffed updatePayload. There are a few downsides of this approach: - If only "children" has changed, we end up scheduling an update to be done in the commit phase. Since we traverse through it anyway, it's probably not much extra. - It does more work in the commit phase so for a large tree that is mostly unchanged, it'll stall longer. - It does some extra work for special cases since that work happens if anything has changed. We no longer have a deep bailout. - The special cases now have to each replicate the "clean up old props" loop, leading to extra code. The benefit is that this doesn't allocate temporary extra objects (possibly multiple per element if the array has to resize). It's less work overall. It also gives us an option to reuse this function for a sync render optimization. Another benefit is that if we do the loop in the commit phase I can do further optimizations by reading all props that I need for special cases in that loop instead of polymorphic reads from props. This is what I'd like to do in future refactors that would be stacked on top of this change.
2023-04-11 07:09:28 +08:00
import {diffInCommitPhase} from 'shared/ReactFeatureFlags';
[react-native] Use path-based imports instead of Haste for the RN renderer (#15604) * [react-native] Use path-based imports instead of Haste for the RN renderer To move React Native to standard path-based imports instead of Haste, the RN renderer that is generated from the code in this repo needs to use path-based imports as well since the generated code is vendored by RN. This commit makes it so the interface between the generated renderers and RN does not rely on Haste and instead uses a private interface explicitly defined by RN. This inverts control of the abstraction so that RN decides the internals to export rather than React deciding what to import. On RN's side, a new module named `react-native/Libraries/ReactPrivate/ReactNativePrivateInterface` explicitly exports the modules used by the renderers in this repo. (There is also a private module for InitializeCore so that we can import it just for the side effects.) On React's side, the various renderer modules access RN internals through the explicit private interface. The Rollup configuration becomes slimmer since the only external package is now `react-native`, and the individual modules are instead listed out in `ReactNativePrivateInterface`. Task description: https://github.com/facebook/react-native/issues/24770 Sister RN PR (needs to land before this one): https://github.com/facebook/react-native/pull/24782 Test Plan: Ran unit tests and Flow in this repo. Generated the renderers and manually copied them over to the RN repo. Ran the RN tests and launched the RNTester app. * Access natively defined "nativeFabricUIManager" instead of importing it Some places in the Fabric renderers access `nativeFabricUIManager` (a natively defined global) instead of importing UIManager. While this is coupling across repos that depends on the timing of events, it is necessary until we have a way to defer top-level imports to run after `nativeFabricUIManager` is defined. So for consistency we use `nativeFabricUIManager` everywhere (see the comment in https://github.com/facebook/react/pull/15604#pullrequestreview-236842223 for more context).
2019-05-23 15:23:54 +08:00
const {get: getViewConfigForType} = ReactNativeViewConfigRegistry;
// Counter for uniquely identifying views.
// % 10 === 1 means it is a rootTag.
// % 2 === 0 means it is a Fabric tag.
// This means that they never overlap.
let nextReactTag = 2;
type InternalInstanceHandle = Object;
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
type Node = Object;
export type Type = string;
export type Props = Object;
export type Instance = {
Extracted definition and access to public instances to a separate module in Fabric (#26321) ## Summary The current definition of `Instance` in Fabric has 2 fields: - `node`: reference to the native node in the shadow tree. - `canonical`: public instance provided to users via refs + some internal fields needed by Fabric. We're currently using `canonical` not only as the public instance, but also to store internal properties that Fabric needs to access in different parts of the codebase. Those properties are, in fact, available through refs as well, which breaks encapsulation. This PR splits that into 2 separate fields, leaving the definition of instance as: - `node`: reference to the native node in the shadow tree. - `publicInstance`: public instance provided to users via refs. - Rest of internal fields needed by Fabric at the instance level. This also migrates all the current usages of `canonical` to use the right property depending on the use case. To improve encapsulation (and in preparation for the implementation of this [proposal to bring some DOM APIs to public instances in React Native](https://github.com/react-native-community/discussions-and-proposals/pull/607)), this also **moves the creation of and the access to the public instance to separate modules** (`ReactFabricPublicInstance` and `ReactFabricPublicInstanceUtils`). In a following diff, that module will be moved into the `react-native` repository and we'll access it through `ReactNativePrivateInterface`. ## How did you test this change? Existing unit tests. Manually synced the PR in Meta infra and tested in Catalyst + the integration with DevTools. Everything is working normally.
2023-03-13 21:25:42 +08:00
// Reference to the shadow node.
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
node: Node,
// This object is shared by all the clones of the instance.
// We use it to access their shared public instance (exposed through refs)
// and to access its committed state for events, etc.
canonical: {
nativeTag: number,
viewConfig: ViewConfig,
currentProps: Props,
// Reference to the React handle (the fiber)
internalInstanceHandle: InternalInstanceHandle,
// Exposed through refs.
publicInstance: PublicInstance,
},
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
};
export type TextInstance = {
// Reference to the shadow node.
node: Node,
// Text instances are never cloned, so we don't need to keep a "canonical"
// reference to make sure all clones of the instance point to the same values.
publicInstance?: PublicTextInstance,
};
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
export type HydratableInstance = Instance | TextInstance;
export type PublicInstance = ReactNativePublicInstance;
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
export type Container = number;
export type ChildSet = Object;
export type HostContext = $ReadOnly<{
isInAParentText: boolean,
}>;
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
export type UpdatePayload = Object;
export type TimeoutHandle = TimeoutID;
export type NoTimeout = -1;
export type TransitionStatus = mixed;
export type RendererInspectionConfig = $ReadOnly<{
// Deprecated. Replaced with getInspectorDataForViewAtPoint.
getInspectorDataForViewTag?: (tag: number) => Object,
getInspectorDataForViewAtPoint?: (
inspectedView: Object,
locationX: number,
locationY: number,
callback: (viewData: TouchedViewDataAtPoint) => mixed,
) => void,
}>;
// TODO: Remove this conditional once all changes have propagated.
if (registerEventHandler) {
/**
* Register the event emitter with the native bridge
*/
registerEventHandler(dispatchEvent);
}
export * from 'react-reconciler/src/ReactFiberConfigWithNoMutation';
export * from 'react-reconciler/src/ReactFiberConfigWithNoHydration';
export * from 'react-reconciler/src/ReactFiberConfigWithNoScopes';
export * from 'react-reconciler/src/ReactFiberConfigWithNoTestSelectors';
export * from 'react-reconciler/src/ReactFiberConfigWithNoMicrotasks';
export * from 'react-reconciler/src/ReactFiberConfigWithNoResources';
export * from 'react-reconciler/src/ReactFiberConfigWithNoSingletons';
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
export function appendInitialChild(
parentInstance: Instance,
child: Instance | TextInstance,
): void {
appendChildNode(parentInstance.node, child.node);
}
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
export function createInstance(
type: string,
props: Props,
rootContainerInstance: Container,
hostContext: HostContext,
internalInstanceHandle: InternalInstanceHandle,
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
): Instance {
const tag = nextReactTag;
nextReactTag += 2;
const viewConfig = getViewConfigForType(type);
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
if (__DEV__) {
for (const key in viewConfig.validAttributes) {
if (props.hasOwnProperty(key)) {
deepFreezeAndThrowOnMutationInDev(props[key]);
}
}
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
}
const updatePayload = create(props, viewConfig.validAttributes);
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
const node = createNode(
tag, // reactTag
viewConfig.uiViewClassName, // viewName
rootContainerInstance, // rootTag
updatePayload, // props
internalInstanceHandle, // internalInstanceHandle
);
Extracted definition and access to public instances to a separate module in Fabric (#26321) ## Summary The current definition of `Instance` in Fabric has 2 fields: - `node`: reference to the native node in the shadow tree. - `canonical`: public instance provided to users via refs + some internal fields needed by Fabric. We're currently using `canonical` not only as the public instance, but also to store internal properties that Fabric needs to access in different parts of the codebase. Those properties are, in fact, available through refs as well, which breaks encapsulation. This PR splits that into 2 separate fields, leaving the definition of instance as: - `node`: reference to the native node in the shadow tree. - `publicInstance`: public instance provided to users via refs. - Rest of internal fields needed by Fabric at the instance level. This also migrates all the current usages of `canonical` to use the right property depending on the use case. To improve encapsulation (and in preparation for the implementation of this [proposal to bring some DOM APIs to public instances in React Native](https://github.com/react-native-community/discussions-and-proposals/pull/607)), this also **moves the creation of and the access to the public instance to separate modules** (`ReactFabricPublicInstance` and `ReactFabricPublicInstanceUtils`). In a following diff, that module will be moved into the `react-native` repository and we'll access it through `ReactNativePrivateInterface`. ## How did you test this change? Existing unit tests. Manually synced the PR in Meta infra and tested in Catalyst + the integration with DevTools. Everything is working normally.
2023-03-13 21:25:42 +08:00
const component = createPublicInstance(
tag,
viewConfig,
internalInstanceHandle,
);
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
return {
node: node,
canonical: {
nativeTag: tag,
viewConfig,
currentProps: props,
internalInstanceHandle,
publicInstance: component,
},
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
};
}
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
export function createTextInstance(
text: string,
rootContainerInstance: Container,
hostContext: HostContext,
internalInstanceHandle: InternalInstanceHandle,
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
): TextInstance {
if (__DEV__) {
if (!hostContext.isInAParentText) {
console.error('Text strings must be rendered within a <Text> component.');
}
}
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
const tag = nextReactTag;
nextReactTag += 2;
const node = createNode(
tag, // reactTag
'RCTRawText', // viewName
rootContainerInstance, // rootTag
{text: text}, // props
internalInstanceHandle, // instance handle
);
return {
node: node,
};
}
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
export function finalizeInitialChildren(
parentInstance: Instance,
type: string,
props: Props,
hostContext: HostContext,
): boolean {
return false;
}
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
export function getRootHostContext(
rootContainerInstance: Container,
): HostContext {
return {isInAParentText: false};
}
export function getChildHostContext(
parentHostContext: HostContext,
type: string,
): HostContext {
const prevIsInAParentText = parentHostContext.isInAParentText;
const isInAParentText =
type === 'AndroidTextInput' || // Android
type === 'RCTMultilineTextInputView' || // iOS
type === 'RCTSinglelineTextInputView' || // iOS
type === 'RCTText' ||
type === 'RCTVirtualText';
[Fabric] Use container node to toggle the visibility of Offscreen and Suspense trees (#21960) * Fix type of Offscreen props argument Fixes an oversight from a previous refactor. The fiber that wraps a Suspense component's children used to be a Fragment but now it's on Offscreen fiber, so its props type has changed. There's a special hydration path where I forgot to update this. This isn't observable because we don't ever end up rendering this particular fiber (because the Suspense boundary is in its fallback state) but we should fix it anyway to avoid a potential regression in the future. * Extract createOffscreenFromFiber logic ...into a new method called `createWorkInProgressOffscreenFiber`. Just for symmetry with `updateWorkInProgressOffscreenFiber`. Doesn't change any behavior. * [Fabric] Use container node to hide/show tree This changes how we hide and show the contents of Offscreen boundaries in the React Fabric renderer (persistent mode), and also Suspense boundaries which use the same feature.= The way it used to work was that when a boundary is hidden, in the complete phase, instead of calling the normal `cloneInstance` method inside `appendAllChildren`, we would call a forked method called `cloneHiddenInstance` for each of the nearest host nodes within the subtree. This design was largely based on how it works in React DOM (mutation mode), where instead of cloning the nearest host nodes, we mutate their `style.display` property. The motivation for doing it this way in React DOM was because there's no built-in browser API for hiding a collection of DOM nodes without affecting their layout. In Fabric, however, there is no such limitation, so we can instead wrap in an extra host node and apply a hidden style. The immediate motivation for this change is that Fabric on Android has a view pooling mechanism for instances that relies on the assumption that a current Fiber that is cloned and replaced by a new Fiber will never appear in a future commit. When this assumption is broken, it may cause crashes. In the current implementation, that can indeed happen when a node that was previously hidden is toggled back to visible. Although this change sidesteps the issue, we may introduce in other features in the future that would benefit from being able to revert back to an older node without cloning it again, such as animations. The way I've implemented this is to insert an additional HostComponent fiber as the child of each OffscreenComponent. The extra fiber is not ideal — the way I'd prefer to do it is to attach the host instance to the OffscreenComponent. However, the native Fabric implementation currently expects a 1:1 correspondence between HostComponents and host instances, so I've deferred that optimization to a future PR to derisk fixing the Fabric pooling crash. I left a TODO in the host config with a description of the remaining steps, but this alone should be sufficient to unblock.
2021-07-27 04:17:08 +08:00
// TODO: If this is an offscreen host container, we should reuse the
// parent context.
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
if (prevIsInAParentText !== isInAParentText) {
return {isInAParentText};
} else {
return parentHostContext;
}
}
export function getPublicInstance(instance: Instance): null | PublicInstance {
if (instance.canonical != null && instance.canonical.publicInstance != null) {
return instance.canonical.publicInstance;
}
Extracted definition and access to public instances to a separate module in Fabric (#26321) ## Summary The current definition of `Instance` in Fabric has 2 fields: - `node`: reference to the native node in the shadow tree. - `canonical`: public instance provided to users via refs + some internal fields needed by Fabric. We're currently using `canonical` not only as the public instance, but also to store internal properties that Fabric needs to access in different parts of the codebase. Those properties are, in fact, available through refs as well, which breaks encapsulation. This PR splits that into 2 separate fields, leaving the definition of instance as: - `node`: reference to the native node in the shadow tree. - `publicInstance`: public instance provided to users via refs. - Rest of internal fields needed by Fabric at the instance level. This also migrates all the current usages of `canonical` to use the right property depending on the use case. To improve encapsulation (and in preparation for the implementation of this [proposal to bring some DOM APIs to public instances in React Native](https://github.com/react-native-community/discussions-and-proposals/pull/607)), this also **moves the creation of and the access to the public instance to separate modules** (`ReactFabricPublicInstance` and `ReactFabricPublicInstanceUtils`). In a following diff, that module will be moved into the `react-native` repository and we'll access it through `ReactNativePrivateInterface`. ## How did you test this change? Existing unit tests. Manually synced the PR in Meta infra and tested in Catalyst + the integration with DevTools. Everything is working normally.
2023-03-13 21:25:42 +08:00
// For compatibility with the legacy renderer, in case it's used with Fabric
// in the same app.
// $FlowExpectedError[prop-missing]
if (instance._nativeTag != null) {
Extracted definition and access to public instances to a separate module in Fabric (#26321) ## Summary The current definition of `Instance` in Fabric has 2 fields: - `node`: reference to the native node in the shadow tree. - `canonical`: public instance provided to users via refs + some internal fields needed by Fabric. We're currently using `canonical` not only as the public instance, but also to store internal properties that Fabric needs to access in different parts of the codebase. Those properties are, in fact, available through refs as well, which breaks encapsulation. This PR splits that into 2 separate fields, leaving the definition of instance as: - `node`: reference to the native node in the shadow tree. - `publicInstance`: public instance provided to users via refs. - Rest of internal fields needed by Fabric at the instance level. This also migrates all the current usages of `canonical` to use the right property depending on the use case. To improve encapsulation (and in preparation for the implementation of this [proposal to bring some DOM APIs to public instances in React Native](https://github.com/react-native-community/discussions-and-proposals/pull/607)), this also **moves the creation of and the access to the public instance to separate modules** (`ReactFabricPublicInstance` and `ReactFabricPublicInstanceUtils`). In a following diff, that module will be moved into the `react-native` repository and we'll access it through `ReactNativePrivateInterface`. ## How did you test this change? Existing unit tests. Manually synced the PR in Meta infra and tested in Catalyst + the integration with DevTools. Everything is working normally.
2023-03-13 21:25:42 +08:00
// $FlowExpectedError[incompatible-return]
return instance;
}
return null;
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
}
function getPublicTextInstance(
textInstance: TextInstance,
internalInstanceHandle: InternalInstanceHandle,
): PublicTextInstance {
if (textInstance.publicInstance == null) {
textInstance.publicInstance = createPublicTextInstance(
internalInstanceHandle,
);
}
return textInstance.publicInstance;
}
export function getPublicInstanceFromInternalInstanceHandle(
internalInstanceHandle: InternalInstanceHandle,
): null | PublicInstance | PublicTextInstance {
if (internalInstanceHandle.tag === HostText) {
const textInstance: TextInstance = internalInstanceHandle.stateNode;
return getPublicTextInstance(textInstance, internalInstanceHandle);
}
const instance: Instance = internalInstanceHandle.stateNode;
return getPublicInstance(instance);
}
export function prepareForCommit(containerInfo: Container): null | Object {
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
// Noop
return null;
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
}
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
export function prepareUpdate(
instance: Instance,
type: string,
oldProps: Props,
newProps: Props,
hostContext: HostContext,
): null | Object {
Diff properties in the commit phase instead of generating an update payload (#26583) This removes the concept of `prepareUpdate()`, behind a flag. React Native already does everything in the commit phase, but generates a temporary update payload before applying it. React Fabric does it both in the render phase. Now it just moves it to a single host config. For DOM I forked updateProperties into one that does diffing and updating in one pass vs just applying a pre-diffed updatePayload. There are a few downsides of this approach: - If only "children" has changed, we end up scheduling an update to be done in the commit phase. Since we traverse through it anyway, it's probably not much extra. - It does more work in the commit phase so for a large tree that is mostly unchanged, it'll stall longer. - It does some extra work for special cases since that work happens if anything has changed. We no longer have a deep bailout. - The special cases now have to each replicate the "clean up old props" loop, leading to extra code. The benefit is that this doesn't allocate temporary extra objects (possibly multiple per element if the array has to resize). It's less work overall. It also gives us an option to reuse this function for a sync render optimization. Another benefit is that if we do the loop in the commit phase I can do further optimizations by reading all props that I need for special cases in that loop instead of polymorphic reads from props. This is what I'd like to do in future refactors that would be stacked on top of this change.
2023-04-11 07:09:28 +08:00
if (diffInCommitPhase) {
return null;
}
const viewConfig = instance.canonical.viewConfig;
const updatePayload = diff(oldProps, newProps, viewConfig.validAttributes);
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
// TODO: If the event handlers have changed, we need to update the current props
// in the commit phase but there is no host config hook to do it yet.
// So instead we hack it by updating it in the render phase.
instance.canonical.currentProps = newProps;
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
return updatePayload;
}
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
export function resetAfterCommit(containerInfo: Container): void {
// Noop
}
export function shouldSetTextContent(type: string, props: Props): boolean {
// TODO (bvaughn) Revisit this decision.
// Always returning false simplifies the createInstance() implementation,
// But creates an additional child Fiber for raw text children.
// No additional native views are created though.
// It's not clear to me which is better so I'm deferring for now.
// More context @ github.com/facebook/react/pull/8560#discussion_r92111303
return false;
}
export function getCurrentEventPriority(): * {
const currentEventPriority = fabricGetCurrentEventPriority
? fabricGetCurrentEventPriority()
: null;
if (currentEventPriority != null) {
switch (currentEventPriority) {
case FabricDiscretePriority:
return DiscreteEventPriority;
case FabricDefaultPriority:
default:
return DefaultEventPriority;
}
}
return DefaultEventPriority;
}
Synchronously flush the transition lane scheduled in a popstate event (#26025) <!-- Thanks for submitting a pull request! We appreciate you spending the time to work on these changes. Please provide enough information so that others can review your pull request. The three fields below are mandatory. Before submitting a pull request, please make sure the following is done: 1. Fork [the repository](https://github.com/facebook/react) and create your branch from `main`. 2. Run `yarn` in the repository root. 3. If you've fixed a bug or added code that should be tested, add tests! 4. Ensure the test suite passes (`yarn test`). Tip: `yarn test --watch TestName` is helpful in development. 5. Run `yarn test --prod` to test in the production environment. It supports the same options as `yarn test`. 6. If you need a debugger, run `yarn debug-test --watch TestName`, open `chrome://inspect`, and press "Inspect". 7. Format your code with [prettier](https://github.com/prettier/prettier) (`yarn prettier`). 8. Make sure your code lints (`yarn lint`). Tip: `yarn linc` to only check changed files. 9. Run the [Flow](https://flowtype.org/) type checks (`yarn flow`). 10. If you haven't already, complete the CLA. Learn more about contributing: https://reactjs.org/docs/how-to-contribute.html --> ## Summary Browsers restore state like forms and scroll position right after the popstate event. To make sure the page work as expected on back or forward button, we need to flush transitions scheduled in a popstate synchronously, and only yields if it suspends. This PR adds a new HostConfig method to check if `window.event === 'popstate'`, and `scheduleMicrotask` if a transition is scheduled in a `PopStateEvent`. ## How did you test this change? yarn test
2023-04-14 03:21:19 +08:00
export function shouldAttemptEagerTransition(): boolean {
return false;
}
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
// The Fabric renderer is secondary to the existing React Native renderer.
export const isPrimaryRenderer = false;
// The Fabric renderer shouldn't trigger missing act() warnings
export const warnsIfNotActing = false;
export const scheduleTimeout = setTimeout;
export const cancelTimeout = clearTimeout;
export const noTimeout = -1;
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
// -------------------
// Persistence
// -------------------
export const supportsPersistence = true;
export function cloneInstance(
instance: Instance,
updatePayload: null | Object,
type: string,
oldProps: Props,
newProps: Props,
internalInstanceHandle: InternalInstanceHandle,
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
keepChildren: boolean,
recyclableInstance: null | Instance,
): Instance {
Diff properties in the commit phase instead of generating an update payload (#26583) This removes the concept of `prepareUpdate()`, behind a flag. React Native already does everything in the commit phase, but generates a temporary update payload before applying it. React Fabric does it both in the render phase. Now it just moves it to a single host config. For DOM I forked updateProperties into one that does diffing and updating in one pass vs just applying a pre-diffed updatePayload. There are a few downsides of this approach: - If only "children" has changed, we end up scheduling an update to be done in the commit phase. Since we traverse through it anyway, it's probably not much extra. - It does more work in the commit phase so for a large tree that is mostly unchanged, it'll stall longer. - It does some extra work for special cases since that work happens if anything has changed. We no longer have a deep bailout. - The special cases now have to each replicate the "clean up old props" loop, leading to extra code. The benefit is that this doesn't allocate temporary extra objects (possibly multiple per element if the array has to resize). It's less work overall. It also gives us an option to reuse this function for a sync render optimization. Another benefit is that if we do the loop in the commit phase I can do further optimizations by reading all props that I need for special cases in that loop instead of polymorphic reads from props. This is what I'd like to do in future refactors that would be stacked on top of this change.
2023-04-11 07:09:28 +08:00
if (diffInCommitPhase) {
const viewConfig = instance.canonical.viewConfig;
updatePayload = diff(oldProps, newProps, viewConfig.validAttributes);
// TODO: If the event handlers have changed, we need to update the current props
// in the commit phase but there is no host config hook to do it yet.
// So instead we hack it by updating it in the render phase.
instance.canonical.currentProps = newProps;
}
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
const node = instance.node;
let clone;
if (keepChildren) {
if (updatePayload !== null) {
clone = cloneNodeWithNewProps(node, updatePayload);
} else {
Diff properties in the commit phase instead of generating an update payload (#26583) This removes the concept of `prepareUpdate()`, behind a flag. React Native already does everything in the commit phase, but generates a temporary update payload before applying it. React Fabric does it both in the render phase. Now it just moves it to a single host config. For DOM I forked updateProperties into one that does diffing and updating in one pass vs just applying a pre-diffed updatePayload. There are a few downsides of this approach: - If only "children" has changed, we end up scheduling an update to be done in the commit phase. Since we traverse through it anyway, it's probably not much extra. - It does more work in the commit phase so for a large tree that is mostly unchanged, it'll stall longer. - It does some extra work for special cases since that work happens if anything has changed. We no longer have a deep bailout. - The special cases now have to each replicate the "clean up old props" loop, leading to extra code. The benefit is that this doesn't allocate temporary extra objects (possibly multiple per element if the array has to resize). It's less work overall. It also gives us an option to reuse this function for a sync render optimization. Another benefit is that if we do the loop in the commit phase I can do further optimizations by reading all props that I need for special cases in that loop instead of polymorphic reads from props. This is what I'd like to do in future refactors that would be stacked on top of this change.
2023-04-11 07:09:28 +08:00
if (diffInCommitPhase) {
// No changes
return instance;
} else {
clone = cloneNode(node);
}
}
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
} else {
if (updatePayload !== null) {
clone = cloneNodeWithNewChildrenAndProps(node, updatePayload);
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
} else {
clone = cloneNodeWithNewChildren(node);
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
}
}
return {
node: clone,
canonical: instance.canonical,
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
};
}
export function cloneHiddenInstance(
instance: Instance,
type: string,
props: Props,
internalInstanceHandle: InternalInstanceHandle,
): Instance {
const viewConfig = instance.canonical.viewConfig;
const node = instance.node;
const updatePayload = create(
{style: {display: 'none'}},
viewConfig.validAttributes,
);
return {
node: cloneNodeWithNewProps(node, updatePayload),
canonical: instance.canonical,
};
}
export function cloneHiddenTextInstance(
instance: Instance,
text: string,
internalInstanceHandle: InternalInstanceHandle,
): TextInstance {
throw new Error('Not yet implemented.');
}
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
export function createContainerChildSet(container: Container): ChildSet {
return createChildNodeSet(container);
}
export function appendChildToContainerChildSet(
childSet: ChildSet,
child: Instance | TextInstance,
): void {
appendChildNodeToSet(childSet, child.node);
}
export function finalizeContainerChildren(
container: Container,
newChildren: ChildSet,
): void {
completeRoot(container, newChildren);
}
Resolve host configs at build time (#12792) * Extract base Jest config This makes it easier to change the source config without affecting the build test config. * Statically import the host config This changes react-reconciler to import HostConfig instead of getting it through a function argument. Rather than start with packages like ReactDOM that want to inline it, I started with React Noop and ensured that *custom* renderers using react-reconciler package still work. To do this, I'm making HostConfig module in the reconciler look at a global variable by default (which, in case of the react-reconciler npm package, ends up being the host config argument in the top-level scope). This is still very broken. * Add scaffolding for importing an inlined renderer * Fix the build * ES exports for renderer methods * ES modules for host configs * Remove closures from the reconciler * Check each renderer's config with Flow * Fix uncovered Flow issue We know nextHydratableInstance doesn't get mutated inside this function, but Flow doesn't so it thinks it may be null. Help Flow. * Prettier * Get rid of enable*Reconciler flags They are not as useful anymore because for almost all cases (except third party renderers) we *know* whether it supports mutation or persistence. This refactoring means react-reconciler and react-reconciler/persistent third-party packages now ship the same thing. Not ideal, but this seems worth how simpler the code becomes. We can later look into addressing it by having a single toggle instead. * Prettier again * Fix Flow config creation issue * Fix imprecise Flow typing * Revert accidental changes
2018-05-19 18:29:11 +08:00
export function replaceContainerChildren(
container: Container,
newChildren: ChildSet,
): void {}
export function getInstanceFromNode(node: any): empty {
throw new Error('Not yet implemented.');
}
export function beforeActiveInstanceBlur(
internalInstanceHandle: InternalInstanceHandle,
) {
// noop
}
export function afterActiveInstanceBlur() {
// noop
}
export function preparePortalMount(portalInstance: Instance): void {
// noop
}
export function detachDeletedInstance(node: Instance): void {
// noop
}
export function requestPostPaintCallback(callback: (time: number) => void) {
// noop
}
Check if suspensey instance resolves in immediate task (#26427) When rendering a suspensey resource that we haven't seen before, it may have loaded in the background while we were rendering. We should yield to the main thread to see if the load event fires in an immediate task. For example, if the resource for a link element has already loaded, its load event will fire in a task right after React yields to the main thread. Because the continuation task is not scheduled until right before React yields, the load event will ping React before it resumes. If this happens, we can resume rendering without showing a fallback. I don't think this matters much for images, because the `completed` property tells us whether the image has loaded, and during a non-urgent render, we never block the main thread for more than 5ms at a time (for now — we might increase this in the future). It matters more for stylesheets because the only way to check if it has loaded is by listening for the load event. This is essentially the same trick that `use` does for userspace promises, but a bit simpler because we don't need to replay the host component's begin phase; the work-in-progress fiber already completed, so we can just continue onto the next sibling without any additional work. As part of this change, I split the `shouldSuspendCommit` host config method into separate `maySuspendCommit` and `preloadInstance` methods. Previously `shouldSuspendCommit` was used for both. This raised a question of whether we should preload resources during a synchronous render. My initial instinct was that we shouldn't, because we're going to synchronously block the main thread until the resource is inserted into the DOM, anyway. But I wonder if the browser is able to initiate the preload even while the main thread is blocked. It's probably a micro-optimization either way because most resources will be loaded during transitions, not urgent renders.
2023-03-21 00:35:10 +08:00
export function maySuspendCommit(type: Type, props: Props): boolean {
Feature: Suspend commit without blocking render (#26398) This adds a new capability for renderers (React DOM, React Native): prevent a tree from being displayed until it is ready, showing a fallback if necessary, but without blocking the React components from being evaluated in the meantime. A concrete example is CSS loading: React DOM can block a commit from being applied until the stylesheet has loaded. This allows us to load the CSS asynchronously, while also preventing a flash of unstyled content. Images and fonts are some of the other use cases. You can think of this as "Suspense for the commit phase". Traditional Suspense, i.e. with `use`, blocking during the render phase: React cannot proceed with rendering until the data is available. But in the case of things like stylesheets, you don't need the CSS in order to evaluate the component. It just needs to be loaded before the tree is committed. Because React buffers its side effects and mutations, it can do work in parallel while the stylesheets load in the background. Like regular Suspense, a "suspensey" stylesheet or image will trigger the nearest Suspense fallback if it hasn't loaded yet. For now, though, we only do this for non-urgent updates, like with startTransition. If you render a suspensey resource during an urgent update, it will revert to today's behavior. (We may or may not add a way to suspend the commit during an urgent update in the future.) In this PR, I have implemented this capability in the reconciler via new methods added to the host config. I've used our internal React "no-op" renderer to write tests that demonstrate the feature. I have not yet implemented Suspensey CSS, images, etc in React DOM. @gnoff and I will work on that in subsequent PRs.
2023-03-18 06:05:11 +08:00
return false;
}
Check if suspensey instance resolves in immediate task (#26427) When rendering a suspensey resource that we haven't seen before, it may have loaded in the background while we were rendering. We should yield to the main thread to see if the load event fires in an immediate task. For example, if the resource for a link element has already loaded, its load event will fire in a task right after React yields to the main thread. Because the continuation task is not scheduled until right before React yields, the load event will ping React before it resumes. If this happens, we can resume rendering without showing a fallback. I don't think this matters much for images, because the `completed` property tells us whether the image has loaded, and during a non-urgent render, we never block the main thread for more than 5ms at a time (for now — we might increase this in the future). It matters more for stylesheets because the only way to check if it has loaded is by listening for the load event. This is essentially the same trick that `use` does for userspace promises, but a bit simpler because we don't need to replay the host component's begin phase; the work-in-progress fiber already completed, so we can just continue onto the next sibling without any additional work. As part of this change, I split the `shouldSuspendCommit` host config method into separate `maySuspendCommit` and `preloadInstance` methods. Previously `shouldSuspendCommit` was used for both. This raised a question of whether we should preload resources during a synchronous render. My initial instinct was that we shouldn't, because we're going to synchronously block the main thread until the resource is inserted into the DOM, anyway. But I wonder if the browser is able to initiate the preload even while the main thread is blocked. It's probably a micro-optimization either way because most resources will be loaded during transitions, not urgent renders.
2023-03-21 00:35:10 +08:00
export function preloadInstance(type: Type, props: Props): boolean {
return true;
}
Feature: Suspend commit without blocking render (#26398) This adds a new capability for renderers (React DOM, React Native): prevent a tree from being displayed until it is ready, showing a fallback if necessary, but without blocking the React components from being evaluated in the meantime. A concrete example is CSS loading: React DOM can block a commit from being applied until the stylesheet has loaded. This allows us to load the CSS asynchronously, while also preventing a flash of unstyled content. Images and fonts are some of the other use cases. You can think of this as "Suspense for the commit phase". Traditional Suspense, i.e. with `use`, blocking during the render phase: React cannot proceed with rendering until the data is available. But in the case of things like stylesheets, you don't need the CSS in order to evaluate the component. It just needs to be loaded before the tree is committed. Because React buffers its side effects and mutations, it can do work in parallel while the stylesheets load in the background. Like regular Suspense, a "suspensey" stylesheet or image will trigger the nearest Suspense fallback if it hasn't loaded yet. For now, though, we only do this for non-urgent updates, like with startTransition. If you render a suspensey resource during an urgent update, it will revert to today's behavior. (We may or may not add a way to suspend the commit during an urgent update in the future.) In this PR, I have implemented this capability in the reconciler via new methods added to the host config. I've used our internal React "no-op" renderer to write tests that demonstrate the feature. I have not yet implemented Suspensey CSS, images, etc in React DOM. @gnoff and I will work on that in subsequent PRs.
2023-03-18 06:05:11 +08:00
export function startSuspendingCommit(): void {}
export function suspendInstance(type: Type, props: Props): void {}
export function waitForCommitToBeReady(): null {
return null;
}
export const NotPendingTransition: TransitionStatus = null;