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
90 changes: 79 additions & 11 deletions packages/react-dom-bindings/src/client/ReactDOMComponentTree.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ import {getParentHydrationBoundary} from './ReactFiberConfigDOM';

import {enableScopeAPI} from 'shared/ReactFeatureFlags';

import {enableInternalInstanceMap} from 'shared/ReactFeatureFlags';

const randomKey = Math.random().toString(36).slice(2);
const internalInstanceKey = '__reactFiber$' + randomKey;
const internalPropsKey = '__reactProps$' + randomKey;
Expand All @@ -49,7 +51,32 @@ const internalRootNodeResourcesKey = '__reactResources$' + randomKey;
const internalHoistableMarker = '__reactMarker$' + randomKey;
const internalScrollTimer = '__reactScroll$' + randomKey;

type InstanceUnion =
| Instance
| TextInstance
| SuspenseInstance
| ActivityInstance
| ReactScopeInstance
| Container;

const PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map;
const internalInstanceMap:
| WeakMap<InstanceUnion, Fiber>
| Map<InstanceUnion, Fiber> = new PossiblyWeakMap();
const internalPropsMap:
| WeakMap<InstanceUnion, Props>
| Map<InstanceUnion, Props> = new PossiblyWeakMap();

export function detachDeletedInstance(node: Instance): void {
if (enableInternalInstanceMap) {
internalInstanceMap.delete(node);
internalPropsMap.delete(node);
delete (node: any)[internalEventHandlersKey];
delete (node: any)[internalEventHandlerListenersKey];
delete (node: any)[internalEventHandlesSetKey];
delete (node: any)[internalRootNodeResourcesKey];
return;
}
// TODO: This function is only called on host components. I don't think all of
// these fields are relevant.
delete (node: any)[internalInstanceKey];
Expand All @@ -68,6 +95,10 @@ export function precacheFiberNode(
| ActivityInstance
| ReactScopeInstance,
): void {
if (enableInternalInstanceMap) {
internalInstanceMap.set(node, hostInst);
return;
}
(node: any)[internalInstanceKey] = hostInst;
}

Expand Down Expand Up @@ -95,7 +126,12 @@ export function isContainerMarkedAsRoot(node: Container): boolean {
// HostRoot back. To get to the HostRoot, you need to pass a child of it.
// The same thing applies to Suspense and Activity boundaries.
export function getClosestInstanceFromNode(targetNode: Node): null | Fiber {
let targetInst = (targetNode: any)[internalInstanceKey];
let targetInst: void | Fiber;
if (enableInternalInstanceMap) {
targetInst = internalInstanceMap.get(((targetNode: any): InstanceUnion));
} else {
targetInst = (targetNode: any)[internalInstanceKey];
}
if (targetInst) {
// Don't return HostRoot, SuspenseComponent or ActivityComponent here.
return targetInst;
Expand All @@ -112,9 +148,15 @@ export function getClosestInstanceFromNode(targetNode: Node): null | Fiber {
// itself because the fibers are conceptually between the container
// node and the first child. It isn't surrounding the container node.
// If it's not a container, we check if it's an instance.
targetInst =
(parentNode: any)[internalContainerInstanceKey] ||
(parentNode: any)[internalInstanceKey];
if (enableInternalInstanceMap) {
targetInst =
(parentNode: any)[internalContainerInstanceKey] ||
internalInstanceMap.get(((parentNode: any): InstanceUnion));
Comment on lines +153 to +154
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

below you check internalInstanceMap first instead of the node itself, is it intentional to have different precedence in different places?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this version I've moved the main instance handle into the internal map but left the container instance handle on the node. So I'm mirroring the existing checks in terms of precedence. This one checks for container first while the other falls back to container.

} else {
targetInst =
(parentNode: any)[internalContainerInstanceKey] ||
(parentNode: any)[internalInstanceKey];
}
if (targetInst) {
// Since this wasn't the direct target of the event, we might have
// stepped past dehydrated DOM nodes to get here. However they could
Expand Down Expand Up @@ -147,8 +189,10 @@ export function getClosestInstanceFromNode(targetNode: Node): null | Fiber {
// have had an internalInstanceKey on it.
// Let's get the fiber associated with the SuspenseComponent
// as the deepest instance.
// $FlowFixMe[prop-missing]
const targetFiber = hydrationInstance[internalInstanceKey];
const targetFiber = enableInternalInstanceMap
? internalInstanceMap.get(hydrationInstance)
: // $FlowFixMe[prop-missing]
hydrationInstance[internalInstanceKey];
if (targetFiber) {
return targetFiber;
}
Expand All @@ -175,9 +219,16 @@ export function getClosestInstanceFromNode(targetNode: Node): null | Fiber {
* instance, or null if the node was not rendered by this React.
*/
export function getInstanceFromNode(node: Node): Fiber | null {
const inst =
(node: any)[internalInstanceKey] ||
(node: any)[internalContainerInstanceKey];
let inst: void | null | Fiber;
if (enableInternalInstanceMap) {
inst =
internalInstanceMap.get(((node: any): InstanceUnion)) ||
(node: any)[internalContainerInstanceKey];
Comment on lines +225 to +226
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

compare to here for example

} else {
inst =
(node: any)[internalInstanceKey] ||
(node: any)[internalContainerInstanceKey];
}
if (inst) {
const tag = inst.tag;
if (
Expand Down Expand Up @@ -226,16 +277,24 @@ export function getFiberCurrentPropsFromNode(
| TextInstance
| SuspenseInstance
| ActivityInstance,
): Props {
): Props | null {
if (enableInternalInstanceMap) {
return internalPropsMap.get(node) || null;
}
return (node: any)[internalPropsKey] || null;
}

export function updateFiberProps(node: Instance, props: Props): void {
if (enableInternalInstanceMap) {
internalPropsMap.set(node, props);
return;
}
(node: any)[internalPropsKey] = props;
}

export function getEventListenerSet(node: EventTarget): Set<string> {
let elementListenerSet = (node: any)[internalEventHandlersKey];
let elementListenerSet: Set<string> | void;
elementListenerSet = (node: any)[internalEventHandlersKey];
if (elementListenerSet === undefined) {
elementListenerSet = (node: any)[internalEventHandlersKey] = new Set();
}
Expand All @@ -246,6 +305,9 @@ export function getFiberFromScopeInstance(
scope: ReactScopeInstance,
): null | Fiber {
if (enableScopeAPI) {
if (enableInternalInstanceMap) {
return internalInstanceMap.get(((scope: any): InstanceUnion)) || null;
}
return (scope: any)[internalInstanceKey] || null;
}
return null;
Expand Down Expand Up @@ -318,6 +380,12 @@ export function clearScrollEndTimer(node: EventTarget): void {
}

export function isOwnedInstance(node: Node): boolean {
if (enableInternalInstanceMap) {
return !!(
(node: any)[internalHoistableMarker] ||
internalInstanceMap.has((node: any))
);
}
return !!(
(node: any)[internalHoistableMarker] || (node: any)[internalInstanceKey]
);
Expand Down
2 changes: 2 additions & 0 deletions packages/shared/ReactFeatureFlags.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ export const enableFragmentRefs: boolean = true;
export const enableFragmentRefsScrollIntoView: boolean = true;
export const enableFragmentRefsInstanceHandles: boolean = false;

export const enableInternalInstanceMap: boolean = false;

// -----------------------------------------------------------------------------
// Ready for next major.
//
Expand Down
1 change: 1 addition & 0 deletions packages/shared/forks/ReactFeatureFlags.native-fb.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export const enableComponentPerformanceTrack: boolean =
__PROFILE__ && dynamicFlags.enableComponentPerformanceTrack;
export const enablePerformanceIssueReporting: boolean =
enableComponentPerformanceTrack;
export const enableInternalInstanceMap: boolean = false;

// Flow magic to verify the exports of this file match the original version.
((((null: any): ExportsType): FeatureFlagsType): ExportsType);
2 changes: 2 additions & 0 deletions packages/shared/forks/ReactFeatureFlags.native-oss.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ export const enableFragmentRefs: boolean = true;
export const enableFragmentRefsScrollIntoView: boolean = false;
export const enableFragmentRefsInstanceHandles: boolean = false;

export const enableInternalInstanceMap: boolean = false;

// Profiling Only
export const enableProfilerTimer: boolean = __PROFILE__;
export const enableProfilerCommitHooks: boolean = __PROFILE__;
Expand Down
2 changes: 2 additions & 0 deletions packages/shared/forks/ReactFeatureFlags.test-renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ export const enableFragmentRefs: boolean = true;
export const enableFragmentRefsScrollIntoView: boolean = true;
export const enableFragmentRefsInstanceHandles: boolean = false;

export const enableInternalInstanceMap: boolean = false;

// TODO: This must be in sync with the main ReactFeatureFlags file because
// the Test Renderer's value must be the same as the one used by the
// react package.
Expand Down
2 changes: 2 additions & 0 deletions packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,5 +85,7 @@ export const enableFragmentRefsScrollIntoView: boolean = false;
export const enableFragmentRefsInstanceHandles: boolean = false;
export const ownerStackLimit = 1e4;

export const enableInternalInstanceMap: boolean = false;

// Flow magic to verify the exports of this file match the original version.
((((null: any): ExportsType): FeatureFlagsType): ExportsType);
2 changes: 2 additions & 0 deletions packages/shared/forks/ReactFeatureFlags.www-dynamic.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ export const enableFragmentRefs: boolean = __VARIANT__;
export const enableFragmentRefsScrollIntoView: boolean = __VARIANT__;
export const enableAsyncDebugInfo: boolean = __VARIANT__;

export const enableInternalInstanceMap: boolean = __VARIANT__;

// TODO: These flags are hard-coded to the default values used in open source.
// Update the tests so that they pass in either mode, then set these
// to __VARIANT__.
Expand Down
1 change: 1 addition & 0 deletions packages/shared/forks/ReactFeatureFlags.www.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export const {
enableFragmentRefs,
enableFragmentRefsScrollIntoView,
enableAsyncDebugInfo,
enableInternalInstanceMap,
} = dynamicFeatureFlags;

// On WWW, __EXPERIMENTAL__ is used for a new modern build.
Expand Down
Loading