Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions packages/react-native-renderer/src/ReactFabric.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@ import {
import {getPublicInstanceFromInternalInstanceHandle} from './ReactFiberConfigFabric';

// Module provided by RN:
import {ReactFiberErrorDialog} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
import {
ReactFiberErrorDialog,
createPublicRootInstance,
type PublicRootInstance,
} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
import {disableLegacyMode} from 'shared/ReactFeatureFlags';

if (typeof ReactFiberErrorDialog.showErrorDialog !== 'function') {
Expand Down Expand Up @@ -126,10 +130,16 @@ function render(
onRecoverableError = options.onRecoverableError;
}

const publicRootInstance = createPublicRootInstance(containerTag);
const rootInstance = {
publicInstance: publicRootInstance,
containerTag,
};

// TODO (bvaughn): If we decide to keep the wrapper component,
// We could create a wrapper for containerTag as well to reduce special casing.
root = createContainer(
containerTag,
rootInstance,
concurrentRoot ? ConcurrentRoot : LegacyRoot,
null,
false,
Expand All @@ -140,6 +150,7 @@ function render(
onRecoverableError,
null,
);

roots.set(containerTag, root);
}
updateContainer(element, root, null, callback);
Expand All @@ -157,6 +168,9 @@ function stopSurface(containerTag: number) {
if (root) {
// TODO: Is it safe to reset this now or should I wait since this unmount could be deferred?
updateContainer(null, root, null, () => {
// Remove the reference to the public instance to prevent memory leaks.
root.containerInfo.publicInstance = null;

roots.delete(containerTag);
});
}
Expand All @@ -170,6 +184,16 @@ function createPortal(
return createPortalImpl(children, containerTag, null, key);
}

function getPublicInstanceFromRootTag(
rootTag: number,
): PublicRootInstance | null {
const root = roots.get(rootTag);
if (root) {
return root.containerInfo.publicInstance;
}
return null;
}

setBatchingImplementation(batchedUpdatesImpl, discreteUpdates);

const roots = new Map<number, FiberRoot>();
Expand All @@ -195,6 +219,8 @@ export {
// instance handles we use to dispatch events. This provides a way to access
// the public instances we created from them (potentially created lazily).
getPublicInstanceFromInternalInstanceHandle,
// Returns the document instance for that root tag.
getPublicInstanceFromRootTag,
// DEV-only:
isChildPublicInstance,
};
Expand Down
15 changes: 10 additions & 5 deletions packages/react-native-renderer/src/ReactFiberConfigFabric.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
createPublicTextInstance,
type PublicInstance as ReactNativePublicInstance,
type PublicTextInstance,
type PublicRootInstance,
} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';

const {
Expand Down Expand Up @@ -108,7 +109,10 @@ export type TextInstance = {
};
export type HydratableInstance = Instance | TextInstance;
export type PublicInstance = ReactNativePublicInstance;
export type Container = number;
export type Container = {
containerTag: number,
publicInstance: PublicRootInstance | null,
};
export type ChildSet = Object | Array<Node>;
export type HostContext = $ReadOnly<{
isInAParentText: boolean,
Expand Down Expand Up @@ -180,7 +184,7 @@ export function createInstance(
const node = createNode(
tag, // reactTag
viewConfig.uiViewClassName, // viewName
rootContainerInstance, // rootTag
rootContainerInstance.containerTag, // rootTag
updatePayload, // props
internalInstanceHandle, // internalInstanceHandle
);
Expand All @@ -189,6 +193,7 @@ export function createInstance(
tag,
viewConfig,
internalInstanceHandle,
rootContainerInstance.publicInstance,
);

return {
Expand Down Expand Up @@ -221,7 +226,7 @@ export function createTextInstance(
const node = createNode(
tag, // reactTag
'RCTRawText', // viewName
rootContainerInstance, // rootTag
rootContainerInstance.containerTag, // rootTag
{text: text}, // props
internalInstanceHandle, // instance handle
);
Expand Down Expand Up @@ -501,7 +506,7 @@ export function finalizeContainerChildren(
newChildren: ChildSet,
): void {
if (!enableFabricCompleteRootInCommitPhase) {
completeRoot(container, newChildren);
completeRoot(container.containerTag, newChildren);
}
}

Expand All @@ -511,7 +516,7 @@ export function replaceContainerChildren(
): void {
// Noop - children will be replaced in finalizeContainerChildren
if (enableFabricCompleteRootInCommitPhase) {
completeRoot(container, newChildren);
completeRoot(container.containerTag, newChildren);
}
}

Expand Down
14 changes: 9 additions & 5 deletions packages/react-native-renderer/src/ReactFiberConfigNative.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
ReactNativeViewConfigRegistry,
UIManager,
deepFreezeAndThrowOnMutationInDev,
type PublicRootInstance,
} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';

import {create, diff} from './ReactNativeAttributePayload';
Expand Down Expand Up @@ -54,7 +55,10 @@ const {get: getViewConfigForType} = ReactNativeViewConfigRegistry;

export type Type = string;
export type Props = Object;
export type Container = number;
export type Container = {
containerTag: number,
publicInstance: PublicRootInstance | null,
};
export type Instance = ReactNativeFiberHostComponent;
export type TextInstance = number;
export type HydratableInstance = Instance | TextInstance;
Expand Down Expand Up @@ -143,7 +147,7 @@ export function createInstance(
UIManager.createView(
tag, // reactTag
viewConfig.uiViewClassName, // viewName
rootContainerInstance, // rootTag
rootContainerInstance.containerTag, // rootTag
updatePayload, // props
);

Expand Down Expand Up @@ -176,7 +180,7 @@ export function createTextInstance(
UIManager.createView(
tag, // reactTag
'RCTRawText', // viewName
rootContainerInstance, // rootTag
rootContainerInstance.containerTag, // rootTag
{text: text}, // props
);

Expand Down Expand Up @@ -349,7 +353,7 @@ export function appendChildToContainer(
): void {
const childTag = typeof child === 'number' ? child : child._nativeTag;
UIManager.setChildren(
parentInstance, // containerTag
parentInstance.containerTag, // containerTag
[childTag], // reactTags
);
}
Expand Down Expand Up @@ -479,7 +483,7 @@ export function removeChildFromContainer(
): void {
recursivelyUncacheFiberNode(child);
UIManager.manageChildren(
parentInstance, // containerID
parentInstance.containerTag, // containerID
[], // moveFromIndices
[], // moveToIndices
[], // addChildReactTags
Expand Down
9 changes: 8 additions & 1 deletion packages/react-native-renderer/src/ReactNativeRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type {ReactPortal, ReactNodeList} from 'shared/ReactTypes';
import type {ElementRef, ElementType, MixedElement} from 'react';
import type {FiberRoot} from 'react-reconciler/src/ReactInternalTypes';
import type {RenderRootOptions} from './ReactNativeTypes';
import type {Container} from 'react-reconciler/src/ReactFiberConfig';

import './ReactNativeInjection';

Expand Down Expand Up @@ -143,10 +144,16 @@ function render(
onRecoverableError = options.onRecoverableError;
}

const rootInstance: Container = {
containerTag,
// $FlowExpectedError[incompatible-type] the legacy renderer does not use public root instances
publicInstance: null,
};

// TODO (bvaughn): If we decide to keep the wrapper component,
// We could create a wrapper for containerTag as well to reduce special casing.
root = createContainer(
containerTag,
rootInstance,
LegacyRoot,
null,
false,
Expand Down
1 change: 1 addition & 0 deletions packages/react-native-renderer/src/ReactNativeTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ export opaque type Node = mixed;
export opaque type InternalInstanceHandle = mixed;
type PublicInstance = mixed;
type PublicTextInstance = mixed;
export opaque type PublicRootInstance = mixed;

export type ReactFabricType = {
findHostInstance_DEPRECATED<TElementType: ElementType>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

export opaque type PublicInstance = mixed;
export opaque type PublicTextInstance = mixed;
export opaque type PublicRootInstance = mixed;

module.exports = {
get BatchedBridge() {
Expand Down Expand Up @@ -59,4 +60,7 @@ module.exports = {
get createPublicTextInstance() {
return require('./createPublicTextInstance').default;
},
get createPublicRootInstance() {
return require('./createPublicRootInstance').default;
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,20 @@
* @flow strict
*/

import type {PublicInstance} from './ReactNativePrivateInterface';
import type {
PublicInstance,
PublicRootInstance,
} from './ReactNativePrivateInterface';

export default function createPublicInstance(
tag: number,
viewConfig: mixed,
internalInstanceHandle: mixed,
rootPublicInstance: PublicRootInstance | null,
): PublicInstance {
return {
__nativeTag: tag,
__internalInstanceHandle: internalInstanceHandle,
__rootPublicInstance: rootPublicInstance,
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* 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 strict
*/

import type {PublicRootInstance} from './ReactNativePrivateInterface';

export default function createPublicRootInstance(
rootTag: number,
): PublicRootInstance {
return null;
}
5 changes: 5 additions & 0 deletions scripts/flow/react-native-host-hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ declare module 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface'
};
declare export opaque type PublicInstance;
declare export opaque type PublicTextInstance;
declare export opaque type PublicRootInstance;
declare export function getNodeFromPublicInstance(
publicInstance: PublicInstance,
): Object;
Expand All @@ -153,7 +154,11 @@ declare module 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface'
tag: number,
viewConfig: __ViewConfig,
internalInstanceHandle: mixed,
publicRootInstance: PublicRootInstance | null,
): PublicInstance;
declare export function createPublicRootInstance(
rootTag: number,
): PublicRootInstance;
declare export function createPublicTextInstance(
internalInstanceHandle: mixed,
): PublicTextInstance;
Expand Down
Loading