@samitouri / QOS-React-2 / commits / ce4b3e9981

[react-interactions] Add optional searchNodes to Scope.queryAllNodes (#17293)

Dominic Gannaway committed Nov 6, 2019 at 22:52 UTC ce4b3e998191445b2934f6846ee7661578ef6444
3 files changed +58 -5
packages/react-reconciler/src/ReactFiberScope.js
+13 -5
@@ -37,12 +37,17 @@ function collectScopedNodes(
37 node: Fiber,
38 fn: (type: string | Object, props: Object) => boolean,
39 scopedNodes: Array<any>,
40 + searchNode: null | Set<Object>,
41 ): void {
42 if (enableScopeAPI) {
43 if (node.tag === HostComponent) {
44 + const instance = getPublicInstance(node.stateNode);
45 const {type, memoizedProps} = node;
44 - if (fn(type, memoizedProps || emptyObject) === true) {
45 - scopedNodes.push(getPublicInstance(node.stateNode));
46 + if (
47 + (searchNode !== null && searchNode.has(instance)) ||
48 + fn(type, memoizedProps || emptyObject) === true
49 + ) {
50 + scopedNodes.push(instance);
51 }
52 }
53 let child = node.child;
@@ -51,7 +56,7 @@ function collectScopedNodes(
56 child = getSuspenseFallbackChild(node);
57 }
58 if (child !== null) {
54 - collectScopedNodesFromChildren(child, fn, scopedNodes);
59 + collectScopedNodesFromChildren(child, fn, scopedNodes, searchNode);
60 }
61 }
62 }
@@ -83,10 +88,11 @@ function collectScopedNodesFromChildren(
88 startingChild: Fiber,
89 fn: (type: string | Object, props: Object) => boolean,
90 scopedNodes: Array<any>,
91 + searchNode: null | Set<Object>,
92 ): void {
93 let child = startingChild;
94 while (child !== null) {
89 - collectScopedNodes(child, fn, scopedNodes);
95 + collectScopedNodes(child, fn, scopedNodes, searchNode);
96 child = child.sibling;
97 }
98 }
@@ -192,12 +198,14 @@ export function createScopeMethods(
198 },
199 queryAllNodes(
200 fn: (type: string | Object, props: Object) => boolean,
201 + searchNodes?: Array<Object>,
202 ): null | Array<Object> {
203 const currentFiber = ((instance.fiber: any): Fiber);
204 const child = currentFiber.child;
205 const scopedNodes = [];
206 + const searchNodeSet = searchNodes ? new Set(searchNodes) : null;
207 if (child !== null) {
200 - collectScopedNodesFromChildren(child, fn, scopedNodes);
208 + collectScopedNodesFromChildren(child, fn, scopedNodes, searchNodeSet);
209 }
210 return scopedNodes.length === 0 ? null : scopedNodes;
211 },
packages/react-reconciler/src/__tests__/ReactScope-test.internal.js
+44
@@ -72,6 +72,50 @@ describe('ReactScope', () => {
72 expect(scopeRef.current).toBe(null);
73 });
74
75 + it('queryAllNodes() works as intended with included nodes array', () => {
76 + const testScopeQuery = (type, props) => type === 'div';
77 + const TestScope = React.unstable_createScope();
78 + const scopeRef = React.createRef();
79 + const divRef = React.createRef();
80 + const spanRef = React.createRef();
81 + const aRef = React.createRef();
82 +
83 + function Test({toggle}) {
84 + return toggle ? (
85 + <TestScope ref={scopeRef}>
86 + <div ref={divRef}>DIV</div>
87 + <span ref={spanRef}>SPAN</span>
88 + <a ref={aRef}>A</a>
89 + </TestScope>
90 + ) : (
91 + <TestScope ref={scopeRef}>
92 + <a ref={aRef}>A</a>
93 + <div ref={divRef}>DIV</div>
94 + <span ref={spanRef}>SPAN</span>
95 + </TestScope>
96 + );
97 + }
98 +
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]);
103 + expect(nodes).toEqual([divRef.current, spanRef.current]);
104 + nodes = scopeRef.current.queryAllNodes(testScopeQuery, [
105 + spanRef.current,
106 + aRef.current,
107 + ]);
108 + expect(nodes).toEqual([divRef.current, spanRef.current, aRef.current]);
109 + ReactDOM.render(<Test toggle={false} />, container);
110 + nodes = scopeRef.current.queryAllNodes(testScopeQuery, [
111 + spanRef.current,
112 + aRef.current,
113 + ]);
114 + expect(nodes).toEqual([aRef.current, divRef.current, spanRef.current]);
115 + ReactDOM.render(null, container);
116 + expect(scopeRef.current).toBe(null);
117 + });
118 +
119 it('queryFirstNode() works as intended', () => {
120 const testScopeQuery = (type, props) => true;
121 const TestScope = React.unstable_createScope();
packages/shared/ReactTypes.js
+1
@@ -171,6 +171,7 @@ export type ReactScopeMethods = {|
171 getProps(): Object,
172 queryAllNodes(
173 (type: string | Object, props: Object) => boolean,
174 + searchNodes?: Array<Object>,
175 ): null | Array<Object>,
176 queryFirstNode(
177 (type: string | Object, props: Object) => boolean,