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

This commit is contained in:
Dominic Gannaway 2019-11-06 22:52:59 +00:00 committed by GitHub
parent dee03049f5
commit ce4b3e9981
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 58 additions and 5 deletions

View File

@ -37,12 +37,17 @@ function collectScopedNodes(
node: Fiber, node: Fiber,
fn: (type: string | Object, props: Object) => boolean, fn: (type: string | Object, props: Object) => boolean,
scopedNodes: Array<any>, scopedNodes: Array<any>,
searchNode: null | Set<Object>,
): void { ): void {
if (enableScopeAPI) { if (enableScopeAPI) {
if (node.tag === HostComponent) { if (node.tag === HostComponent) {
const instance = getPublicInstance(node.stateNode);
const {type, memoizedProps} = node; const {type, memoizedProps} = node;
if (fn(type, memoizedProps || emptyObject) === true) { if (
scopedNodes.push(getPublicInstance(node.stateNode)); (searchNode !== null && searchNode.has(instance)) ||
fn(type, memoizedProps || emptyObject) === true
) {
scopedNodes.push(instance);
} }
} }
let child = node.child; let child = node.child;
@ -51,7 +56,7 @@ function collectScopedNodes(
child = getSuspenseFallbackChild(node); child = getSuspenseFallbackChild(node);
} }
if (child !== null) { if (child !== null) {
collectScopedNodesFromChildren(child, fn, scopedNodes); collectScopedNodesFromChildren(child, fn, scopedNodes, searchNode);
} }
} }
} }
@ -83,10 +88,11 @@ function collectScopedNodesFromChildren(
startingChild: Fiber, startingChild: Fiber,
fn: (type: string | Object, props: Object) => boolean, fn: (type: string | Object, props: Object) => boolean,
scopedNodes: Array<any>, scopedNodes: Array<any>,
searchNode: null | Set<Object>,
): void { ): void {
let child = startingChild; let child = startingChild;
while (child !== null) { while (child !== null) {
collectScopedNodes(child, fn, scopedNodes); collectScopedNodes(child, fn, scopedNodes, searchNode);
child = child.sibling; child = child.sibling;
} }
} }
@ -192,12 +198,14 @@ export function createScopeMethods(
}, },
queryAllNodes( queryAllNodes(
fn: (type: string | Object, props: Object) => boolean, fn: (type: string | Object, props: Object) => boolean,
searchNodes?: Array<Object>,
): null | Array<Object> { ): null | Array<Object> {
const currentFiber = ((instance.fiber: any): Fiber); const currentFiber = ((instance.fiber: any): Fiber);
const child = currentFiber.child; const child = currentFiber.child;
const scopedNodes = []; const scopedNodes = [];
const searchNodeSet = searchNodes ? new Set(searchNodes) : null;
if (child !== null) { if (child !== null) {
collectScopedNodesFromChildren(child, fn, scopedNodes); collectScopedNodesFromChildren(child, fn, scopedNodes, searchNodeSet);
} }
return scopedNodes.length === 0 ? null : scopedNodes; return scopedNodes.length === 0 ? null : scopedNodes;
}, },

View File

@ -72,6 +72,50 @@ describe('ReactScope', () => {
expect(scopeRef.current).toBe(null); expect(scopeRef.current).toBe(null);
}); });
it('queryAllNodes() works as intended with included nodes array', () => {
const testScopeQuery = (type, props) => type === 'div';
const TestScope = React.unstable_createScope();
const scopeRef = React.createRef();
const divRef = React.createRef();
const spanRef = React.createRef();
const aRef = React.createRef();
function Test({toggle}) {
return toggle ? (
<TestScope ref={scopeRef}>
<div ref={divRef}>DIV</div>
<span ref={spanRef}>SPAN</span>
<a ref={aRef}>A</a>
</TestScope>
) : (
<TestScope ref={scopeRef}>
<a ref={aRef}>A</a>
<div ref={divRef}>DIV</div>
<span ref={spanRef}>SPAN</span>
</TestScope>
);
}
ReactDOM.render(<Test toggle={true} />, container);
let nodes = scopeRef.current.queryAllNodes(testScopeQuery);
expect(nodes).toEqual([divRef.current]);
nodes = scopeRef.current.queryAllNodes(testScopeQuery, [spanRef.current]);
expect(nodes).toEqual([divRef.current, spanRef.current]);
nodes = scopeRef.current.queryAllNodes(testScopeQuery, [
spanRef.current,
aRef.current,
]);
expect(nodes).toEqual([divRef.current, spanRef.current, aRef.current]);
ReactDOM.render(<Test toggle={false} />, container);
nodes = scopeRef.current.queryAllNodes(testScopeQuery, [
spanRef.current,
aRef.current,
]);
expect(nodes).toEqual([aRef.current, divRef.current, spanRef.current]);
ReactDOM.render(null, container);
expect(scopeRef.current).toBe(null);
});
it('queryFirstNode() works as intended', () => { it('queryFirstNode() works as intended', () => {
const testScopeQuery = (type, props) => true; const testScopeQuery = (type, props) => true;
const TestScope = React.unstable_createScope(); const TestScope = React.unstable_createScope();

View File

@ -171,6 +171,7 @@ export type ReactScopeMethods = {|
getProps(): Object, getProps(): Object,
queryAllNodes( queryAllNodes(
(type: string | Object, props: Object) => boolean, (type: string | Object, props: Object) => boolean,
searchNodes?: Array<Object>,
): null | Array<Object>, ): null | Array<Object>,
queryFirstNode( queryFirstNode(
(type: string | Object, props: Object) => boolean, (type: string | Object, props: Object) => boolean,