[react-interactions] Expost host instance to Scope Query function (#17341)
Dominic Gannaway committed
Nov 11, 2019 at 13:51 UTC
6cff70a740d1e6ad10070ebf88514bd3a49d0f0d
3 files changed
+31
-33
packages/react-reconciler/src/ReactFiberScope.js
+17
-20
@@ -35,17 +35,16 @@ const emptyObject = {};
35
36
function collectScopedNodes(
37
node: Fiber,
38
- fn: (type: string | Object, props: Object) => boolean,
38
+ fn: (type: string | Object, props: Object, instance: Object) => boolean,
39
scopedNodes: Array<any>,
40
- searchNode: null | Set<Object>,
40
): void {
41
if (enableScopeAPI) {
42
if (node.tag === HostComponent) {
44
- const instance = getPublicInstance(node.stateNode);
45
- const {type, memoizedProps} = node;
43
+ const {type, memoizedProps, stateNode} = node;
44
+ const instance = getPublicInstance(stateNode);
45
if (
47
- (searchNode !== null && searchNode.has(instance)) ||
48
- fn(type, memoizedProps || emptyObject) === true
46
+ instance !== null &&
47
+ fn(type, memoizedProps || emptyObject, instance) === true
48
) {
49
scopedNodes.push(instance);
50
}
@@ -56,20 +55,21 @@ function collectScopedNodes(
55
child = getSuspenseFallbackChild(node);
56
}
57
if (child !== null) {
59
- collectScopedNodesFromChildren(child, fn, scopedNodes, searchNode);
58
+ collectScopedNodesFromChildren(child, fn, scopedNodes);
59
}
60
}
61
}
62
63
function collectFirstScopedNode(
64
node: Fiber,
66
- fn: (type: string | Object, props: Object) => boolean,
65
+ fn: (type: string | Object, props: Object, instance: Object) => boolean,
66
): null | Object {
67
if (enableScopeAPI) {
68
if (node.tag === HostComponent) {
70
- const {type, memoizedProps} = node;
71
- if (fn(type, memoizedProps) === true) {
72
- return getPublicInstance(node.stateNode);
69
+ const {type, memoizedProps, stateNode} = node;
70
+ const instance = getPublicInstance(stateNode);
71
+ if (instance !== null && fn(type, memoizedProps, instance) === true) {
72
+ return instance;
73
}
74
}
75
let child = node.child;
@@ -86,20 +86,19 @@ function collectFirstScopedNode(
86
87
function collectScopedNodesFromChildren(
88
startingChild: Fiber,
89
- fn: (type: string | Object, props: Object) => boolean,
89
+ fn: (type: string | Object, props: Object, instance: Object) => boolean,
90
scopedNodes: Array<any>,
91
- searchNode: null | Set<Object>,
91
): void {
92
let child = startingChild;
93
while (child !== null) {
95
- collectScopedNodes(child, fn, scopedNodes, searchNode);
94
+ collectScopedNodes(child, fn, scopedNodes);
95
child = child.sibling;
96
}
97
}
98
99
function collectFirstScopedNodeFromChildren(
100
startingChild: Fiber,
102
- fn: (type: string | Object, props: Object) => boolean,
101
+ fn: (type: string | Object, props: Object, instance: Object) => boolean,
102
): Object | null {
103
let child = startingChild;
104
while (child !== null) {
@@ -197,20 +196,18 @@ export function createScopeMethods(
196
return currentFiber.memoizedProps;
197
},
198
queryAllNodes(
200
- fn: (type: string | Object, props: Object) => boolean,
201
- searchNodes?: Array<Object>,
199
+ fn: (type: string | Object, props: Object, instance: Object) => boolean,
200
): null | Array<Object> {
201
const currentFiber = ((instance.fiber: any): Fiber);
202
const child = currentFiber.child;
203
const scopedNodes = [];
206
- const searchNodeSet = searchNodes ? new Set(searchNodes) : null;
204
if (child !== null) {
208
- collectScopedNodesFromChildren(child, fn, scopedNodes, searchNodeSet);
205
+ collectScopedNodesFromChildren(child, fn, scopedNodes);
206
}
207
return scopedNodes.length === 0 ? null : scopedNodes;
208
},
209
queryFirstNode(
213
- fn: (type: string | Object, props: Object) => boolean,
210
+ fn: (type: string | Object, props: Object, instance: Object) => boolean,
211
): null | Object {
212
const currentFiber = ((instance.fiber: any): Fiber);
213
const child = currentFiber.child;
packages/react-reconciler/src/__tests__/ReactScope-test.internal.js
+12
-10
@@ -72,7 +72,7 @@ describe('ReactScope', () => {
72
expect(scopeRef.current).toBe(null);
73
});
74
75
- it('queryAllNodes() works as intended with included nodes array', () => {
75
+ it('queryAllNodes() provides the correct host instance', () => {
76
const testScopeQuery = (type, props) => type === 'div';
77
const TestScope = React.unstable_createScope();
78
const scopeRef = React.createRef();
@@ -99,18 +99,20 @@ describe('ReactScope', () => {
99
ReactDOM.render(<Test toggle={true} />, container);
100
let nodes = scopeRef.current.queryAllNodes(testScopeQuery);
101
expect(nodes).toEqual([divRef.current]);
102
- nodes = scopeRef.current.queryAllNodes(testScopeQuery, [spanRef.current]);
102
+ let filterQuery = (type, props, instance) =>
103
+ instance === spanRef.current || testScopeQuery(type, props);
104
+ nodes = scopeRef.current.queryAllNodes(filterQuery);
105
expect(nodes).toEqual([divRef.current, spanRef.current]);
104
- nodes = scopeRef.current.queryAllNodes(testScopeQuery, [
105
- spanRef.current,
106
- aRef.current,
107
- ]);
106
+ filterQuery = (type, props, instance) =>
107
+ [spanRef.current, aRef.current].includes(instance) ||
108
+ testScopeQuery(type, props);
109
+ nodes = scopeRef.current.queryAllNodes(filterQuery);
110
expect(nodes).toEqual([divRef.current, spanRef.current, aRef.current]);
111
ReactDOM.render(<Test toggle={false} />, container);
110
- nodes = scopeRef.current.queryAllNodes(testScopeQuery, [
111
- spanRef.current,
112
- aRef.current,
113
- ]);
112
+ filterQuery = (type, props, instance) =>
113
+ [spanRef.current, aRef.current].includes(instance) ||
114
+ testScopeQuery(type, props);
115
+ nodes = scopeRef.current.queryAllNodes(filterQuery);
116
expect(nodes).toEqual([aRef.current, divRef.current, spanRef.current]);
117
ReactDOM.render(null, container);
118
expect(scopeRef.current).toBe(null);
packages/shared/ReactTypes.js
+2
-3
@@ -170,11 +170,10 @@ export type ReactScopeMethods = {|
170
getParent(): null | ReactScopeMethods,
171
getProps(): Object,
172
queryAllNodes(
173
- (type: string | Object, props: Object) => boolean,
174
- searchNodes?: Array<Object>,
173
+ (type: string | Object, props: Object, instance: Object) => boolean,
174
): null | Array<Object>,
175
queryFirstNode(
177
- (type: string | Object, props: Object) => boolean,
176
+ (type: string | Object, props: Object, instance: Object) => boolean,
177
): null | Object,
178
containsNode(Object): boolean,
179
|};