Skip to content

Commit aa88589

Browse files
authored
Refine experimental Scopes API (facebook#18778)
* Refine experimental Scopes API
1 parent d804f99 commit aa88589

18 files changed

+240
-144
lines changed

packages/react-art/src/ReactARTHostConfig.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ function applyTextProps(instance, props, prevProps = {}) {
243243

244244
export * from 'react-reconciler/src/ReactFiberHostConfigWithNoPersistence';
245245
export * from 'react-reconciler/src/ReactFiberHostConfigWithNoHydration';
246+
export * from 'react-reconciler/src/ReactFiberHostConfigWithNoScopes';
246247

247248
export function appendInitialChild(parentInstance, child) {
248249
if (typeof child === 'string') {

packages/react-dom/src/client/ReactDOMComponentTree.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*/
99

1010
import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
11+
import type {ReactScopeInstance} from 'shared/ReactTypes';
1112
import type {
1213
Container,
1314
TextInstance,
@@ -23,10 +24,12 @@ import {
2324
HostRoot,
2425
SuspenseComponent,
2526
} from 'react-reconciler/src/ReactWorkTags';
26-
import invariant from 'shared/invariant';
2727

2828
import {getParentSuspenseInstance} from './ReactDOMHostConfig';
2929

30+
import invariant from 'shared/invariant';
31+
import {enableScopeAPI} from 'shared/ReactFeatureFlags';
32+
3033
const randomKey = Math.random()
3134
.toString(36)
3235
.slice(2);
@@ -47,7 +50,7 @@ export type ElementListenerMapEntry = {
4750

4851
export function precacheFiberNode(
4952
hostInst: Fiber,
50-
node: Instance | TextInstance | SuspenseInstance,
53+
node: Instance | TextInstance | SuspenseInstance | ReactScopeInstance,
5154
): void {
5255
(node: any)[internalInstanceKey] = hostInst;
5356
}
@@ -205,3 +208,12 @@ export function getEventListenerMap(node: EventTarget): ElementListenerMap {
205208
}
206209
return elementListenerMap;
207210
}
211+
212+
export function getFiberFromScopeInstance(
213+
scope: ReactScopeInstance,
214+
): null | Fiber {
215+
if (enableScopeAPI) {
216+
return (scope: any)[internalInstanceKey] || null;
217+
}
218+
return null;
219+
}

packages/react-dom/src/client/ReactDOMHostConfig.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import type {TopLevelType} from 'legacy-events/TopLevelEventTypes';
1111
import type {RootType} from './ReactDOMRoot';
12+
import type {ReactScopeInstance} from 'shared/ReactTypes';
1213
import type {
1314
ReactDOMEventResponder,
1415
ReactDOMEventResponderInstance,
@@ -19,6 +20,7 @@ import {
1920
precacheFiberNode,
2021
updateFiberProps,
2122
getClosestInstanceFromNode,
23+
getFiberFromScopeInstance,
2224
} from './ReactDOMComponentTree';
2325
import {
2426
createElement,
@@ -65,6 +67,7 @@ import {
6567
enableDeprecatedFlareAPI,
6668
enableFundamentalAPI,
6769
enableModernEventSystem,
70+
enableScopeAPI,
6871
} from 'shared/ReactFeatureFlags';
6972
import {TOP_BEFORE_BLUR, TOP_AFTER_BLUR} from '../events/DOMTopLevelEventTypes';
7073
import {listenToEvent} from '../events/DOMModernPluginEventSystem';
@@ -1117,3 +1120,25 @@ export function preparePortalMount(portalInstance: Instance): void {
11171120
listenToEvent('onMouseEnter', portalInstance);
11181121
}
11191122
}
1123+
1124+
export function prepareScopeUpdate(
1125+
scopeInstance: ReactScopeInstance,
1126+
internalInstanceHandle: Object,
1127+
): void {
1128+
if (enableScopeAPI) {
1129+
precacheFiberNode(internalInstanceHandle, scopeInstance);
1130+
}
1131+
}
1132+
1133+
export function prepareScopeUnmount(scopeInstance: Object): void {
1134+
// TODO when we add createEventHandle
1135+
}
1136+
1137+
export function getInstanceFromScope(
1138+
scopeInstance: ReactScopeInstance,
1139+
): null | Object {
1140+
if (enableScopeAPI) {
1141+
return getFiberFromScopeInstance(scopeInstance);
1142+
}
1143+
return null;
1144+
}

packages/react-dom/src/events/DOMModernPluginEventSystem.js

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import type {
1414
ElementListenerMapEntry,
1515
} from '../client/ReactDOMComponentTree';
1616
import type {EventSystemFlags} from './EventSystemFlags';
17-
import type {EventPriority, ReactScopeMethods} from 'shared/ReactTypes';
17+
import type {EventPriority} from 'shared/ReactTypes';
1818
import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
1919
import type {PluginModule} from 'legacy-events/PluginModuleType';
2020
import type {ReactSyntheticEvent} from 'legacy-events/ReactSyntheticEventType';
@@ -381,22 +381,6 @@ function isMatchingRootContainer(
381381
);
382382
}
383383

384-
export function isManagedDOMElement(
385-
target: EventTarget | ReactScopeMethods,
386-
): boolean {
387-
return getClosestInstanceFromNode(((target: any): Node)) !== null;
388-
}
389-
390-
export function isValidEventTarget(
391-
target: EventTarget | ReactScopeMethods,
392-
): boolean {
393-
return typeof (target: Object).addEventListener === 'function';
394-
}
395-
396-
export function isReactScope(target: EventTarget | ReactScopeMethods): boolean {
397-
return typeof (target: Object).getChildContextValues === 'function';
398-
}
399-
400384
export function dispatchEventForPluginEventSystem(
401385
topLevelType: DOMTopLevelEventType,
402386
eventSystemFlags: EventSystemFlags,

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ class ReactFabricHostComponent {
183183

184184
export * from 'react-reconciler/src/ReactFiberHostConfigWithNoMutation';
185185
export * from 'react-reconciler/src/ReactFiberHostConfigWithNoHydration';
186+
export * from 'react-reconciler/src/ReactFiberHostConfigWithNoScopes';
186187

187188
export function appendInitialChild(
188189
parentInstance: Instance,

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ function recursivelyUncacheFiberNode(node: Instance | TextInstance) {
8787

8888
export * from 'react-reconciler/src/ReactFiberHostConfigWithNoPersistence';
8989
export * from 'react-reconciler/src/ReactFiberHostConfigWithNoHydration';
90+
export * from 'react-reconciler/src/ReactFiberHostConfigWithNoScopes';
9091

9192
export function appendInitialChild(
9293
parentInstance: Instance,

packages/react-noop-renderer/src/createReactNoop.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,14 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
457457
preparePortalMount() {
458458
// NO-OP
459459
},
460+
461+
prepareScopeUpdate() {},
462+
463+
prepareScopeUnmount() {},
464+
465+
getInstanceFromScope() {
466+
throw new Error('Not yet implemented.');
467+
},
460468
};
461469

462470
const hostConfig = useMutation

packages/react-reconciler/src/ReactFiberCommitWork.new.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ import {
115115
commitHydratedSuspenseInstance,
116116
beforeRemoveInstance,
117117
clearContainer,
118+
prepareScopeUpdate,
119+
prepareScopeUnmount,
118120
} from './ReactFiberHostConfig';
119121
import {
120122
captureCommitPhaseError,
@@ -890,7 +892,7 @@ function commitAttachRef(finishedWork: Fiber) {
890892
}
891893
// Moved outside to ensure DCE works with this flag
892894
if (enableScopeAPI && finishedWork.tag === ScopeComponent) {
893-
instanceToUse = instance.methods;
895+
instanceToUse = instance;
894896
}
895897
if (typeof ref === 'function') {
896898
ref(instanceToUse);
@@ -1065,10 +1067,12 @@ function commitUnmount(
10651067
return;
10661068
}
10671069
case ScopeComponent: {
1068-
if (enableDeprecatedFlareAPI) {
1069-
unmountDeprecatedResponderListeners(current);
1070-
}
10711070
if (enableScopeAPI) {
1071+
if (enableDeprecatedFlareAPI) {
1072+
unmountDeprecatedResponderListeners(current);
1073+
}
1074+
const scopeInstance = current.stateNode;
1075+
prepareScopeUnmount(scopeInstance);
10721076
safelyDetachRef(current);
10731077
}
10741078
return;
@@ -1721,7 +1725,6 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
17211725
case ScopeComponent: {
17221726
if (enableScopeAPI) {
17231727
const scopeInstance = finishedWork.stateNode;
1724-
scopeInstance.fiber = finishedWork;
17251728
if (enableDeprecatedFlareAPI) {
17261729
const newProps = finishedWork.memoizedProps;
17271730
const oldProps = current !== null ? current.memoizedProps : newProps;
@@ -1731,6 +1734,7 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
17311734
updateDeprecatedEventListeners(nextListeners, finishedWork, null);
17321735
}
17331736
}
1737+
prepareScopeUpdate(scopeInstance, finishedWork);
17341738
return;
17351739
}
17361740
break;

packages/react-reconciler/src/ReactFiberCommitWork.old.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ import {
112112
commitHydratedSuspenseInstance,
113113
beforeRemoveInstance,
114114
clearContainer,
115+
prepareScopeUpdate,
116+
prepareScopeUnmount,
115117
} from './ReactFiberHostConfig';
116118
import {
117119
captureCommitPhaseError,
@@ -888,7 +890,7 @@ function commitAttachRef(finishedWork: Fiber) {
888890
}
889891
// Moved outside to ensure DCE works with this flag
890892
if (enableScopeAPI && finishedWork.tag === ScopeComponent) {
891-
instanceToUse = instance.methods;
893+
instanceToUse = instance;
892894
}
893895
if (typeof ref === 'function') {
894896
ref(instanceToUse);
@@ -1063,10 +1065,12 @@ function commitUnmount(
10631065
return;
10641066
}
10651067
case ScopeComponent: {
1066-
if (enableDeprecatedFlareAPI) {
1067-
unmountDeprecatedResponderListeners(current);
1068-
}
10691068
if (enableScopeAPI) {
1069+
if (enableDeprecatedFlareAPI) {
1070+
unmountDeprecatedResponderListeners(current);
1071+
}
1072+
const scopeInstance = current.stateNode;
1073+
prepareScopeUnmount(scopeInstance);
10701074
safelyDetachRef(current);
10711075
}
10721076
return;
@@ -1715,7 +1719,6 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
17151719
case ScopeComponent: {
17161720
if (enableScopeAPI) {
17171721
const scopeInstance = finishedWork.stateNode;
1718-
scopeInstance.fiber = finishedWork;
17191722
if (enableDeprecatedFlareAPI) {
17201723
const newProps = finishedWork.memoizedProps;
17211724
const oldProps = current !== null ? current.memoizedProps : newProps;
@@ -1725,6 +1728,7 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
17251728
updateDeprecatedEventListeners(nextListeners, finishedWork, null);
17261729
}
17271730
}
1731+
prepareScopeUpdate(scopeInstance, finishedWork);
17281732
return;
17291733
}
17301734
break;

packages/react-reconciler/src/ReactFiberCompleteWork.new.js

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ import {
8787
cloneFundamentalInstance,
8888
shouldUpdateFundamentalComponent,
8989
preparePortalMount,
90+
prepareScopeUpdate,
9091
} from './ReactFiberHostConfig';
9192
import {
9293
getRootHostContainer,
@@ -138,7 +139,7 @@ import {createFundamentalStateInstance} from './ReactFiberFundamental.new';
138139
import {Never, isSameOrHigherPriority} from './ReactFiberExpirationTime.new';
139140
import {resetChildFibers} from './ReactChildFiber.new';
140141
import {updateDeprecatedEventListeners} from './ReactFiberDeprecatedEvents.new';
141-
import {createScopeMethods} from './ReactFiberScope.new';
142+
import {createScopeInstance} from './ReactFiberScope.new';
142143

143144
function markUpdate(workInProgress: Fiber) {
144145
// Tag the fiber with an update effect. This turns a Placement into
@@ -1247,13 +1248,8 @@ function completeWork(
12471248
case ScopeComponent: {
12481249
if (enableScopeAPI) {
12491250
if (current === null) {
1250-
const type = workInProgress.type;
1251-
const scopeInstance: ReactScopeInstance = {
1252-
fiber: workInProgress,
1253-
methods: null,
1254-
};
1251+
const scopeInstance: ReactScopeInstance = createScopeInstance();
12551252
workInProgress.stateNode = scopeInstance;
1256-
scopeInstance.methods = createScopeMethods(type, scopeInstance);
12571253
if (enableDeprecatedFlareAPI) {
12581254
const listeners = newProps.DEPRECATED_flareListeners;
12591255
if (listeners != null) {
@@ -1265,6 +1261,7 @@ function completeWork(
12651261
);
12661262
}
12671263
}
1264+
prepareScopeUpdate(scopeInstance, workInProgress);
12681265
if (workInProgress.ref !== null) {
12691266
markRef(workInProgress);
12701267
markUpdate(workInProgress);

packages/react-reconciler/src/ReactFiberCompleteWork.old.js

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ import {
8484
cloneFundamentalInstance,
8585
shouldUpdateFundamentalComponent,
8686
preparePortalMount,
87+
prepareScopeUpdate,
8788
} from './ReactFiberHostConfig';
8889
import {
8990
getRootHostContainer,
@@ -134,7 +135,7 @@ import {createFundamentalStateInstance} from './ReactFiberFundamental.old';
134135
import {Never} from './ReactFiberExpirationTime.old';
135136
import {resetChildFibers} from './ReactChildFiber.old';
136137
import {updateDeprecatedEventListeners} from './ReactFiberDeprecatedEvents.old';
137-
import {createScopeMethods} from './ReactFiberScope.old';
138+
import {createScopeInstance} from './ReactFiberScope.old';
138139

139140
function markUpdate(workInProgress: Fiber) {
140141
// Tag the fiber with an update effect. This turns a Placement into
@@ -1262,13 +1263,8 @@ function completeWork(
12621263
case ScopeComponent: {
12631264
if (enableScopeAPI) {
12641265
if (current === null) {
1265-
const type = workInProgress.type;
1266-
const scopeInstance: ReactScopeInstance = {
1267-
fiber: workInProgress,
1268-
methods: null,
1269-
};
1266+
const scopeInstance: ReactScopeInstance = createScopeInstance();
12701267
workInProgress.stateNode = scopeInstance;
1271-
scopeInstance.methods = createScopeMethods(type, scopeInstance);
12721268
if (enableDeprecatedFlareAPI) {
12731269
const listeners = newProps.DEPRECATED_flareListeners;
12741270
if (listeners != null) {
@@ -1280,6 +1276,7 @@ function completeWork(
12801276
);
12811277
}
12821278
}
1279+
prepareScopeUpdate(scopeInstance, workInProgress);
12831280
if (workInProgress.ref !== null) {
12841281
markRef(workInProgress);
12851282
markUpdate(workInProgress);
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow
8+
*/
9+
10+
import invariant from 'shared/invariant';
11+
12+
// Renderers that don't support React Scopes
13+
// can re-export everything from this module.
14+
15+
function shim(...args: any) {
16+
invariant(
17+
false,
18+
'The current renderer does not support React Scopes. ' +
19+
'This error is likely caused by a bug in React. ' +
20+
'Please file an issue.',
21+
);
22+
}
23+
24+
// React Scopes (when unsupported)
25+
export const prepareScopeUpdate = shim;
26+
export const prepareScopeUnmount = shim;
27+
export const getInstanceFromScope = shim;

0 commit comments

Comments
 (0)