Skip to content

Commit f83903b

Browse files
authored
[RN] Set up test to create public instances lazily in Fabric (facebook#32363)
## Summary In React Native, public instances and internal host nodes are not represented by the same object (ReactNativeElement & shadow nodes vs. just DOM elements), and the only one that's required for rendering is the shadow node. Public instances are generally only necessary when accessed via refs or events, and that usually happens for a small amount of components in the tree. This implements an optimization to create the public instance on demand, instead of eagerly creating it when creating the host node. We expect this to improve performance by reducing the logic we do per node and the number of object allocations. ## How did you test this change? Manually synced the changes to React Native and run Fantom tests and benchmarks, with the flag enabled and disabled. All tests pass in both cases, and benchmarks show a slight but consistent performance improvement.
1 parent 192555b commit f83903b

10 files changed

+61
-19
lines changed

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

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,10 @@ import {
5757
getInspectorDataForInstance,
5858
} from './ReactNativeFiberInspector';
5959

60-
import {passChildrenWhenCloningPersistedNodes} from 'shared/ReactFeatureFlags';
60+
import {
61+
passChildrenWhenCloningPersistedNodes,
62+
enableLazyPublicInstanceInFabric,
63+
} from 'shared/ReactFeatureFlags';
6164
import {REACT_CONTEXT_TYPE} from 'shared/ReactSymbols';
6265
import type {ReactContext} from 'shared/ReactTypes';
6366

@@ -93,8 +96,11 @@ export type Instance = {
9396
currentProps: Props,
9497
// Reference to the React handle (the fiber)
9598
internalInstanceHandle: InternalInstanceHandle,
96-
// Exposed through refs.
97-
publicInstance: PublicInstance,
99+
// Exposed through refs. Potentially lazily created.
100+
publicInstance: PublicInstance | null,
101+
// This is only necessary to lazily create `publicInstance`.
102+
// Will be set to `null` after that is created.
103+
publicRootInstance?: PublicRootInstance | null,
98104
},
99105
};
100106
export type TextInstance = {
@@ -186,23 +192,37 @@ export function createInstance(
186192
internalInstanceHandle, // internalInstanceHandle
187193
);
188194

189-
const component = createPublicInstance(
190-
tag,
191-
viewConfig,
192-
internalInstanceHandle,
193-
rootContainerInstance.publicInstance,
194-
);
195-
196-
return {
197-
node: node,
198-
canonical: {
199-
nativeTag: tag,
195+
if (enableLazyPublicInstanceInFabric) {
196+
return {
197+
node: node,
198+
canonical: {
199+
nativeTag: tag,
200+
viewConfig,
201+
currentProps: props,
202+
internalInstanceHandle,
203+
publicInstance: null,
204+
publicRootInstance: rootContainerInstance.publicInstance,
205+
},
206+
};
207+
} else {
208+
const component = createPublicInstance(
209+
tag,
200210
viewConfig,
201-
currentProps: props,
202211
internalInstanceHandle,
203-
publicInstance: component,
204-
},
205-
};
212+
rootContainerInstance.publicInstance,
213+
);
214+
215+
return {
216+
node: node,
217+
canonical: {
218+
nativeTag: tag,
219+
viewConfig,
220+
currentProps: props,
221+
internalInstanceHandle,
222+
publicInstance: component,
223+
},
224+
};
225+
}
206226
}
207227

208228
export function createTextInstance(
@@ -277,7 +297,18 @@ export function getChildHostContext(
277297
}
278298

279299
export function getPublicInstance(instance: Instance): null | PublicInstance {
280-
if (instance.canonical != null && instance.canonical.publicInstance != null) {
300+
if (instance.canonical != null) {
301+
if (instance.canonical.publicInstance == null) {
302+
instance.canonical.publicInstance = createPublicInstance(
303+
instance.canonical.nativeTag,
304+
instance.canonical.viewConfig,
305+
instance.canonical.internalInstanceHandle,
306+
instance.canonical.publicRootInstance ?? null,
307+
);
308+
// This was only necessary to create the public instance.
309+
instance.canonical.publicRootInstance = null;
310+
}
311+
281312
return instance.canonical.publicInstance;
282313
}
283314

packages/shared/ReactFeatureFlags.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ export const enableUseEffectCRUDOverload = false;
154154

155155
export const enableFastAddPropertiesInDiffing = true;
156156

157+
export const enableLazyPublicInstanceInFabric = false;
158+
157159
// -----------------------------------------------------------------------------
158160
// Ready for next major.
159161
//

packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,4 @@ export const enableUseEffectCRUDOverload = __VARIANT__;
2828
export const enableOwnerStacks = __VARIANT__;
2929
export const enableRemoveConsolePatches = __VARIANT__;
3030
export const enableFastAddPropertiesInDiffing = __VARIANT__;
31+
export const enableLazyPublicInstanceInFabric = __VARIANT__;

packages/shared/forks/ReactFeatureFlags.native-fb.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export const {
3030
enableOwnerStacks,
3131
enableRemoveConsolePatches,
3232
enableFastAddPropertiesInDiffing,
33+
enableLazyPublicInstanceInFabric,
3334
} = dynamicFlags;
3435

3536
// The rest of the flags are static for better dead code elimination.

packages/shared/forks/ReactFeatureFlags.native-oss.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ export const enableYieldingBeforePassive = false;
7272
export const enableThrottledScheduling = false;
7373
export const enableViewTransition = false;
7474
export const enableFastAddPropertiesInDiffing = false;
75+
export const enableLazyPublicInstanceInFabric = false;
7576

7677
// Profiling Only
7778
export const enableProfilerTimer = __PROFILE__;

packages/shared/forks/ReactFeatureFlags.test-renderer.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ export const enableYieldingBeforePassive = true;
7171
export const enableThrottledScheduling = false;
7272
export const enableViewTransition = false;
7373
export const enableFastAddPropertiesInDiffing = true;
74+
export const enableLazyPublicInstanceInFabric = false;
7475

7576
// TODO: This must be in sync with the main ReactFeatureFlags file because
7677
// the Test Renderer's value must be the same as the one used by the

packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ export const enableThrottledScheduling = false;
6969
export const enableViewTransition = false;
7070
export const enableRemoveConsolePatches = false;
7171
export const enableFastAddPropertiesInDiffing = false;
72+
export const enableLazyPublicInstanceInFabric = false;
7273

7374
// Flow magic to verify the exports of this file match the original version.
7475
((((null: any): ExportsType): FeatureFlagsType): ExportsType);

packages/shared/forks/ReactFeatureFlags.test-renderer.www.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ export const enableThrottledScheduling = false;
8484
export const enableViewTransition = false;
8585
export const enableRemoveConsolePatches = false;
8686
export const enableFastAddPropertiesInDiffing = false;
87+
export const enableLazyPublicInstanceInFabric = false;
8788

8889
// Flow magic to verify the exports of this file match the original version.
8990
((((null: any): ExportsType): FeatureFlagsType): ExportsType);

packages/shared/forks/ReactFeatureFlags.www-dynamic.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export const enableSiblingPrerendering = __VARIANT__;
3939
export const enableUseEffectCRUDOverload = __VARIANT__;
4040
export const enableRemoveConsolePatches = __VARIANT__;
4141
export const enableFastAddPropertiesInDiffing = __VARIANT__;
42+
export const enableLazyPublicInstanceInFabric = false;
4243
export const enableViewTransition = __VARIANT__;
4344

4445
// TODO: These flags are hard-coded to the default values used in open source.

packages/shared/forks/ReactFeatureFlags.www.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,5 +110,7 @@ export const disableLegacyMode = true;
110110

111111
export const enableShallowPropDiffing = false;
112112

113+
export const enableLazyPublicInstanceInFabric = false;
114+
113115
// Flow magic to verify the exports of this file match the original version.
114116
((((null: any): ExportsType): FeatureFlagsType): ExportsType);

0 commit comments

Comments
 (0)