From 19b0a1eedad0a3af0b9a06518c7e34ab35894a8a Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Tue, 14 Jan 2020 14:17:23 +0000 Subject: [PATCH] [react-interactions] Add DO_NOT_USE to Scope methods --- .../accessibility/README.md | 63 ---------- .../accessibility/docs/TabbableScopeQuery.md | 2 +- .../accessibility/src/FocusContain.js | 2 +- .../accessibility/src/FocusGroup.js | 18 +-- .../accessibility/src/FocusManager.js | 6 +- .../accessibility/src/FocusTable.js | 46 +++---- .../TabbableScopeQuery-test.internal.js | 4 +- .../src/shared/getTabbableNodes.js | 2 +- .../react-reconciler/src/ReactFiberScope.js | 55 ++++++++- .../src/__tests__/ReactScope-test.internal.js | 112 +++++++++++------- packages/shared/ReactTypes.js | 13 +- 11 files changed, 166 insertions(+), 157 deletions(-) diff --git a/packages/react-interactions/accessibility/README.md b/packages/react-interactions/accessibility/README.md index 582820eec122a..844af1957f141 100644 --- a/packages/react-interactions/accessibility/README.md +++ b/packages/react-interactions/accessibility/README.md @@ -14,74 +14,11 @@ can be found [here](./docs). Note: React Scopes require the internal React flag `enableScopeAPI`. -When creating a scope, a query function is required. The query function is used -when collecting host nodes that match the criteria of the query function. - -```jsx -// This query function only matches host nodes that have the type of "div" -const queryFunction = (type: string, props: Object): boolean => { - if (type === 'div') { - return true; - } - return false; -}; - -// Create the scope with the queryFunction above -const DivOnlyScope = React.unstable_createScope(queryFunction); - -// We can now use this in our components. We need to attach -// a ref so we can get the matching host nodes. -function MyComponent(props) { - const divOnlyScope = useRef(null); - return ( - -
DIV 1
-
DIV 2
-
DIV 3
-
- ); -} - -// Using the ref, we can get the host nodes via getAllNodes() -const divs = divOnlyScope.current.getAllNodes(); - -// [
DIV 1
,
DIV 2
,
DIV 3
] -console.log(divs); -``` - ## React Scope Interface Scopes require a `ref` to access the internal interface of a particular scope. The internal interface (`ReactScopeInterface`) exposes the following scope API: -### getChildren: () => null | Array - -Returns an array of all child `ReactScopeInterface` nodes that are -of scopes of the same type. Returns `null` if there are no child scope nodes. - -### getChildrenFromRoot: () => null | Array - -Similar to `getChildren`, except this applies the same traversal from the root of the -React internal tree instead of from the scope node position. - -### getParent: () => null | ReactScopeInterface - -Returns the parent `ReactScopeInterface` of the scope node or `null` if none exists. - -### getProps: () => Object - -Returns the current `props` object of the scope node. - -### getAllNodes: () => null | Array - -Returns an array of all child host nodes that successfully match when queried using the -query function passed to the scope. Returns `null` if there are no matching host nodes. - -### getFirstNode: () => null | HTMLElement - -Returns the first child host node that successfully matches when queried using the -query function passed to the scope. Returns `null` if there is no matching host node. - ### containsNode: (node: HTMLElement) => boolean Returns `true` or `false` depending on if the given `HTMLElement` is a descendant diff --git a/packages/react-interactions/accessibility/docs/TabbableScopeQuery.md b/packages/react-interactions/accessibility/docs/TabbableScopeQuery.md index 0c942ec4281bb..47fc5dff35503 100644 --- a/packages/react-interactions/accessibility/docs/TabbableScopeQuery.md +++ b/packages/react-interactions/accessibility/docs/TabbableScopeQuery.md @@ -15,7 +15,7 @@ function FocusableNodeCollector(props) { const scope = scopeRef.current; if (scope) { - const tabFocusableNodes = scope.queryAllNodes(tabbableScopeQuery); + const tabFocusableNodes = scope.DO_NOT_USE_queryAllNodes(tabbableScopeQuery); if (tabFocusableNodes && props.onFocusableNodes) { props.onFocusableNodes(tabFocusableNodes); } diff --git a/packages/react-interactions/accessibility/src/FocusContain.js b/packages/react-interactions/accessibility/src/FocusContain.js index 78316af93907d..21c0b3cc894f3 100644 --- a/packages/react-interactions/accessibility/src/FocusContain.js +++ b/packages/react-interactions/accessibility/src/FocusContain.js @@ -71,7 +71,7 @@ export default function FocusContain({ disabled !== true && !scope.containsNode(document.activeElement) ) { - const fistElem = scope.queryFirstNode(scopeQuery); + const fistElem = scope.DO_NOT_USE_queryFirstNode(scopeQuery); if (fistElem !== null) { fistElem.focus(); } diff --git a/packages/react-interactions/accessibility/src/FocusGroup.js b/packages/react-interactions/accessibility/src/FocusGroup.js index ad677b9d6a111..4753127e6dafb 100644 --- a/packages/react-interactions/accessibility/src/FocusGroup.js +++ b/packages/react-interactions/accessibility/src/FocusGroup.js @@ -35,7 +35,7 @@ function focusGroupItem( cell: ReactScopeMethods, event: KeyboardEvent, ): void { - const firstScopedNode = cell.queryFirstNode(scopeQuery); + const firstScopedNode = cell.DO_NOT_USE_queryFirstNode(scopeQuery); if (firstScopedNode !== null) { firstScopedNode.focus(); event.preventDefault(); @@ -46,7 +46,7 @@ function getPreviousGroupItem( group: ReactScopeMethods, currentItem: ReactScopeMethods, ): null | ReactScopeMethods { - const items = group.getChildren(); + const items = group.DO_NOT_USE_getChildren(); if (items !== null) { const currentItemIndex = items.indexOf(currentItem); const wrap = getGroupProps(currentItem).wrap; @@ -63,7 +63,7 @@ function getNextGroupItem( group: ReactScopeMethods, currentItem: ReactScopeMethods, ): null | ReactScopeMethods { - const items = group.getChildren(); + const items = group.DO_NOT_USE_getChildren(); if (items !== null) { const currentItemIndex = items.indexOf(currentItem); const wrap = getGroupProps(currentItem).wrap; @@ -78,9 +78,9 @@ function getNextGroupItem( } function getGroupProps(currentCell: ReactScopeMethods): Object { - const group = currentCell.getParent(); + const group = currentCell.DO_NOT_USE_getParent(); if (group !== null) { - const groupProps = group.getProps(); + const groupProps = group.DO_NOT_USE_getProps(); if (groupProps && groupProps.type === 'group') { return groupProps; } @@ -125,8 +125,8 @@ export function createFocusGroup( onKeyDown(event: KeyboardEvent): void { const currentItem = scopeRef.current; if (currentItem !== null) { - const group = currentItem.getParent(); - const groupProps = group && group.getProps(); + const group = currentItem.DO_NOT_USE_getParent(); + const groupProps = group && group.DO_NOT_USE_getProps(); if (group !== null && groupProps.type === 'group') { const portrait = groupProps.portrait; const key = event.key; @@ -134,10 +134,10 @@ export function createFocusGroup( if (key === 'Tab') { const tabScopeQuery = getGroupProps(currentItem).tabScopeQuery; if (tabScopeQuery) { - const groupScope = currentItem.getParent(); + const groupScope = currentItem.DO_NOT_USE_getParent(); if (groupScope) { const activeNode = document.activeElement; - const nodes = groupScope.queryAllNodes(tabScopeQuery); + const nodes = groupScope.DO_NOT_USE_queryAllNodes(tabScopeQuery); for (let i = 0; i < nodes.length; i++) { const node = nodes[i]; if (node !== activeNode) { diff --git a/packages/react-interactions/accessibility/src/FocusManager.js b/packages/react-interactions/accessibility/src/FocusManager.js index 861f91b594bf0..1fc4fd37e0360 100644 --- a/packages/react-interactions/accessibility/src/FocusManager.js +++ b/packages/react-interactions/accessibility/src/FocusManager.js @@ -16,7 +16,7 @@ export function focusFirst( scopeQuery: (type: string | Object, props: Object) => boolean, scope: ReactScopeMethods, ): void { - const firstNode = scope.queryFirstNode(scopeQuery); + const firstNode = scope.DO_NOT_USE_queryFirstNode(scopeQuery); if (firstNode) { focusElem(firstNode); } @@ -101,7 +101,7 @@ export function focusPrevious( export function getNextScope( scope: ReactScopeMethods, ): null | ReactScopeMethods { - const allScopes = scope.getChildrenFromRoot(); + const allScopes = scope.DO_NOT_USE_getChildrenFromRoot(); if (allScopes === null) { return null; } @@ -115,7 +115,7 @@ export function getNextScope( export function getPreviousScope( scope: ReactScopeMethods, ): null | ReactScopeMethods { - const allScopes = scope.getChildrenFromRoot(); + const allScopes = scope.DO_NOT_USE_getChildrenFromRoot(); if (allScopes === null) { return null; } diff --git a/packages/react-interactions/accessibility/src/FocusTable.js b/packages/react-interactions/accessibility/src/FocusTable.js index aea24b80ed1ab..175878402b4ca 100644 --- a/packages/react-interactions/accessibility/src/FocusTable.js +++ b/packages/react-interactions/accessibility/src/FocusTable.js @@ -42,7 +42,7 @@ function focusScope( cell: ReactScopeMethods, event?: KeyboardEvent, ): void { - const firstScopedNode = cell.queryFirstNode(scopeQuery); + const firstScopedNode = cell.DO_NOT_USE_queryFirstNode(scopeQuery); if (firstScopedNode !== null) { firstScopedNode.focus(); if (event) { @@ -58,13 +58,13 @@ function focusCellByColumnIndex( columnIndex: number, event?: KeyboardEvent, ): void { - const cells = row.getChildren(); + const cells = row.DO_NOT_USE_getChildren(); if (cells !== null) { let colSize = 0; for (let i = 0; i < cells.length; i++) { const cell = cells[i]; if (cell) { - colSize += cell.getProps().colSpan || 1; + colSize += cell.DO_NOT_USE_getProps().colSpan || 1; if (colSize > columnIndex) { focusScope(scopeQuery, cell, event); return; @@ -84,7 +84,7 @@ function getCellIndexes( if (cell === currentCell) { return [i, i + totalColSpan]; } - const colSpan = cell.getProps().colSpan; + const colSpan = cell.DO_NOT_USE_getProps().colSpan; if (colSpan) { totalColSpan += colSpan - 1; } @@ -93,9 +93,9 @@ function getCellIndexes( } function getRowCells(currentCell: ReactScopeMethods) { - const row = currentCell.getParent(); - if (row !== null && row.getProps().type === 'row') { - const cells = row.getChildren(); + const row = currentCell.DO_NOT_USE_getParent(); + if (row !== null && row.DO_NOT_USE_getProps().type === 'row') { + const cells = row.DO_NOT_USE_getChildren(); if (cells !== null) { const [rowIndex, rowIndexWithColSpan] = getCellIndexes( cells, @@ -108,11 +108,11 @@ function getRowCells(currentCell: ReactScopeMethods) { } function getRows(currentCell: ReactScopeMethods) { - const row = currentCell.getParent(); - if (row !== null && row.getProps().type === 'row') { - const table = row.getParent(); - if (table !== null && table.getProps().type === 'table') { - const rows = table.getChildren(); + const row = currentCell.DO_NOT_USE_getParent(); + if (row !== null && row.DO_NOT_USE_getProps().type === 'row') { + const table = row.DO_NOT_USE_getParent(); + if (table !== null && table.DO_NOT_USE_getProps().type === 'table') { + const rows = table.DO_NOT_USE_getChildren(); if (rows !== null) { const columnIndex = rows.indexOf(row); return [rows, columnIndex]; @@ -127,11 +127,11 @@ function triggerNavigateOut( direction: 'left' | 'right' | 'up' | 'down', event, ): void { - const row = currentCell.getParent(); - if (row !== null && row.getProps().type === 'row') { - const table = row.getParent(); + const row = currentCell.DO_NOT_USE_getParent(); + if (row !== null && row.DO_NOT_USE_getProps().type === 'row') { + const table = row.DO_NOT_USE_getParent(); if (table !== null) { - const props = table.getProps(); + const props = table.DO_NOT_USE_getProps(); const onKeyboardOut = props.onKeyboardOut; if (props.type === 'table' && typeof onKeyboardOut === 'function') { onKeyboardOut(direction, event); @@ -143,11 +143,11 @@ function triggerNavigateOut( } function getTableProps(currentCell: ReactScopeMethods): Object { - const row = currentCell.getParent(); - if (row !== null && row.getProps().type === 'row') { - const table = row.getParent(); + const row = currentCell.DO_NOT_USE_getParent(); + if (row !== null && row.DO_NOT_USE_getProps().type === 'row') { + const table = row.DO_NOT_USE_getParent(); if (table !== null) { - return table.getProps(); + return table.DO_NOT_USE_getProps(); } } return {}; @@ -207,12 +207,12 @@ export function createFocusTable( if (key === 'Tab') { const tabScopeQuery = getTableProps(currentCell).tabScopeQuery; if (tabScopeQuery) { - const rowScope = currentCell.getParent(); + const rowScope = currentCell.DO_NOT_USE_getParent(); if (rowScope) { - const tableScope = rowScope.getParent(); + const tableScope = rowScope.DO_NOT_USE_getParent(); if (tableScope) { const activeNode = document.activeElement; - const nodes = tableScope.queryAllNodes(tabScopeQuery); + const nodes = tableScope.DO_NOT_USE_queryAllNodes(tabScopeQuery); for (let i = 0; i < nodes.length; i++) { const node = nodes[i]; if (node !== activeNode) { diff --git a/packages/react-interactions/accessibility/src/__tests__/TabbableScopeQuery-test.internal.js b/packages/react-interactions/accessibility/src/__tests__/TabbableScopeQuery-test.internal.js index 1a286330c775a..a3cd9b2ee6a16 100644 --- a/packages/react-interactions/accessibility/src/__tests__/TabbableScopeQuery-test.internal.js +++ b/packages/react-interactions/accessibility/src/__tests__/TabbableScopeQuery-test.internal.js @@ -35,7 +35,7 @@ describe('TabbableScopeQuery', () => { container = null; }); - it('queryAllNodes() works as intended', () => { + it('DO_NOT_USE_queryAllNodes() works as intended', () => { const scopeRef = React.createRef(); const nodeRefA = React.createRef(); const nodeRefB = React.createRef(); @@ -60,7 +60,7 @@ describe('TabbableScopeQuery', () => { } ReactDOM.render(, container); - let nodes = scopeRef.current.queryAllNodes(tabbableScopeQuery); + let nodes = scopeRef.current.DO_NOT_USE_queryAllNodes(tabbableScopeQuery); expect(nodes).toEqual([ nodeRefA.current, nodeRefB.current, diff --git a/packages/react-interactions/accessibility/src/shared/getTabbableNodes.js b/packages/react-interactions/accessibility/src/shared/getTabbableNodes.js index ed6ec67ba6233..7af8612e5f96f 100644 --- a/packages/react-interactions/accessibility/src/shared/getTabbableNodes.js +++ b/packages/react-interactions/accessibility/src/shared/getTabbableNodes.js @@ -19,7 +19,7 @@ export default function getTabbableNodes( number, null | HTMLElement, ] { - const tabbableNodes = scope.queryAllNodes(scopeQuery); + const tabbableNodes = scope.DO_NOT_USE_queryAllNodes(scopeQuery); if (tabbableNodes === null || tabbableNodes.length === 0) { return [null, null, null, 0, null]; } diff --git a/packages/react-reconciler/src/ReactFiberScope.js b/packages/react-reconciler/src/ReactFiberScope.js index 72bbaa6af375b..a593ef22af416 100644 --- a/packages/react-reconciler/src/ReactFiberScope.js +++ b/packages/react-reconciler/src/ReactFiberScope.js @@ -12,6 +12,7 @@ import type { ReactScope, ReactScopeInstance, ReactScopeMethods, + ReactContext, } from 'shared/ReactTypes'; import {getPublicInstance, getInstanceFromNode} from './ReactFiberHostConfig'; @@ -20,6 +21,7 @@ import { HostComponent, SuspenseComponent, ScopeComponent, + ContextProvider, } from 'shared/ReactWorkTags'; import {enableScopeAPI} from 'shared/ReactFeatureFlags'; @@ -142,6 +144,38 @@ function collectNearestChildScopeMethods( } } +function collectNearestContextValues( + node: Fiber, + context: ReactContext, + childContextValues: Array, +): void { + if (node.tag === ContextProvider && node.type._context === context) { + const contextValue = node.memoizedProps.value; + childContextValues.push(contextValue); + } else { + let child = node.child; + + if (isFiberSuspenseAndTimedOut(node)) { + child = getSuspenseFallbackChild(node); + } + if (child !== null) { + collectNearestChildContextValues(child, context, childContextValues); + } + } +} + +function collectNearestChildContextValues( + startingChild: Fiber | null, + context: ReactContext, + childContextValues: Array, +): void { + let child = startingChild; + while (child !== null) { + collectNearestContextValues(child, context, childContextValues); + child = child.sibling; + } +} + function isValidScopeNode(node, scope) { return ( node.tag === ScopeComponent && @@ -155,7 +189,7 @@ export function createScopeMethods( instance: ReactScopeInstance, ): ReactScopeMethods { return { - getChildren(): null | Array { + DO_NOT_USE_getChildren(): null | Array { const currentFiber = ((instance.fiber: any): Fiber); const child = currentFiber.child; const childrenScopes = []; @@ -164,7 +198,7 @@ export function createScopeMethods( } return childrenScopes.length === 0 ? null : childrenScopes; }, - getChildrenFromRoot(): null | Array { + DO_NOT_USE_getChildrenFromRoot(): null | Array { const currentFiber = ((instance.fiber: any): Fiber); let node = currentFiber; while (node !== null) { @@ -181,7 +215,7 @@ export function createScopeMethods( collectNearestChildScopeMethods(node.child, scope, childrenScopes); return childrenScopes.length === 0 ? null : childrenScopes; }, - getParent(): null | ReactScopeMethods { + DO_NOT_USE_getParent(): null | ReactScopeMethods { let node = ((instance.fiber: any): Fiber).return; while (node !== null) { if (node.tag === ScopeComponent && node.type === scope) { @@ -191,11 +225,11 @@ export function createScopeMethods( } return null; }, - getProps(): Object { + DO_NOT_USE_getProps(): Object { const currentFiber = ((instance.fiber: any): Fiber); return currentFiber.memoizedProps; }, - queryAllNodes( + DO_NOT_USE_queryAllNodes( fn: (type: string | Object, props: Object, instance: Object) => boolean, ): null | Array { const currentFiber = ((instance.fiber: any): Fiber); @@ -206,7 +240,7 @@ export function createScopeMethods( } return scopedNodes.length === 0 ? null : scopedNodes; }, - queryFirstNode( + DO_NOT_USE_queryFirstNode( fn: (type: string | Object, props: Object, instance: Object) => boolean, ): null | Object { const currentFiber = ((instance.fiber: any): Fiber); @@ -230,5 +264,14 @@ export function createScopeMethods( } return false; }, + getChildContextValues(context: ReactContext): Array { + const currentFiber = ((instance.fiber: any): Fiber); + const child = currentFiber.child; + const childContextValues = []; + if (child !== null) { + collectNearestChildContextValues(child, context, childContextValues); + } + return childContextValues; + }, }; } diff --git a/packages/react-reconciler/src/__tests__/ReactScope-test.internal.js b/packages/react-reconciler/src/__tests__/ReactScope-test.internal.js index 300e1ce95b146..bbba67c757629 100644 --- a/packages/react-reconciler/src/__tests__/ReactScope-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactScope-test.internal.js @@ -38,7 +38,7 @@ describe('ReactScope', () => { container = null; }); - it('queryAllNodes() works as intended', () => { + it('DO_NOT_USE_queryAllNodes() works as intended', () => { const testScopeQuery = (type, props) => true; const TestScope = React.unstable_createScope(); const scopeRef = React.createRef(); @@ -63,16 +63,16 @@ describe('ReactScope', () => { } ReactDOM.render(, container); - let nodes = scopeRef.current.queryAllNodes(testScopeQuery); + let nodes = scopeRef.current.DO_NOT_USE_queryAllNodes(testScopeQuery); expect(nodes).toEqual([divRef.current, spanRef.current, aRef.current]); ReactDOM.render(, container); - nodes = scopeRef.current.queryAllNodes(testScopeQuery); + nodes = scopeRef.current.DO_NOT_USE_queryAllNodes(testScopeQuery); expect(nodes).toEqual([aRef.current, divRef.current, spanRef.current]); ReactDOM.render(null, container); expect(scopeRef.current).toBe(null); }); - it('queryAllNodes() provides the correct host instance', () => { + it('DO_NOT_USE_queryAllNodes() provides the correct host instance', () => { const testScopeQuery = (type, props) => type === 'div'; const TestScope = React.unstable_createScope(); const scopeRef = React.createRef(); @@ -97,28 +97,28 @@ describe('ReactScope', () => { } ReactDOM.render(, container); - let nodes = scopeRef.current.queryAllNodes(testScopeQuery); + let nodes = scopeRef.current.DO_NOT_USE_queryAllNodes(testScopeQuery); expect(nodes).toEqual([divRef.current]); let filterQuery = (type, props, instance) => instance === spanRef.current || testScopeQuery(type, props); - nodes = scopeRef.current.queryAllNodes(filterQuery); + nodes = scopeRef.current.DO_NOT_USE_queryAllNodes(filterQuery); expect(nodes).toEqual([divRef.current, spanRef.current]); filterQuery = (type, props, instance) => [spanRef.current, aRef.current].includes(instance) || testScopeQuery(type, props); - nodes = scopeRef.current.queryAllNodes(filterQuery); + nodes = scopeRef.current.DO_NOT_USE_queryAllNodes(filterQuery); expect(nodes).toEqual([divRef.current, spanRef.current, aRef.current]); ReactDOM.render(, container); filterQuery = (type, props, instance) => [spanRef.current, aRef.current].includes(instance) || testScopeQuery(type, props); - nodes = scopeRef.current.queryAllNodes(filterQuery); + nodes = scopeRef.current.DO_NOT_USE_queryAllNodes(filterQuery); expect(nodes).toEqual([aRef.current, divRef.current, spanRef.current]); ReactDOM.render(null, container); expect(scopeRef.current).toBe(null); }); - it('queryFirstNode() works as intended', () => { + it('DO_NOT_USE_queryFirstNode() works as intended', () => { const testScopeQuery = (type, props) => true; const TestScope = React.unstable_createScope(); const scopeRef = React.createRef(); @@ -143,10 +143,10 @@ describe('ReactScope', () => { } ReactDOM.render(, container); - let node = scopeRef.current.queryFirstNode(testScopeQuery); + let node = scopeRef.current.DO_NOT_USE_queryFirstNode(testScopeQuery); expect(node).toEqual(divRef.current); ReactDOM.render(, container); - node = scopeRef.current.queryFirstNode(testScopeQuery); + node = scopeRef.current.DO_NOT_USE_queryFirstNode(testScopeQuery); expect(node).toEqual(aRef.current); ReactDOM.render(null, container); expect(scopeRef.current).toBe(null); @@ -201,7 +201,7 @@ describe('ReactScope', () => { expect(scopeRef.current.containsNode(emRef.current)).toBe(false); }); - it('mixed getParent() and queryAllNodes() works as intended', () => { + it('mixed DO_NOT_USE_getParent() and queryAllNodes() works as intended', () => { const testScopeQuery = (type, props) => true; const TestScope = React.unstable_createScope(); const TestScope2 = React.unstable_createScope(); @@ -237,26 +237,26 @@ describe('ReactScope', () => { } ReactDOM.render(, container); - const dParent = refD.current.getParent(); + const dParent = refD.current.DO_NOT_USE_getParent(); expect(dParent).not.toBe(null); - expect(dParent.queryAllNodes(testScopeQuery)).toEqual([ + expect(dParent.DO_NOT_USE_queryAllNodes(testScopeQuery)).toEqual([ divA.current, spanB.current, divB.current, ]); - const cParent = refC.current.getParent(); + const cParent = refC.current.DO_NOT_USE_getParent(); expect(cParent).not.toBe(null); - expect(cParent.queryAllNodes(testScopeQuery)).toEqual([ + expect(cParent.DO_NOT_USE_queryAllNodes(testScopeQuery)).toEqual([ spanA.current, divA.current, spanB.current, divB.current, ]); - expect(refB.current.getParent()).toBe(null); - expect(refA.current.getParent()).toBe(null); + expect(refB.current.DO_NOT_USE_getParent()).toBe(null); + expect(refA.current.DO_NOT_USE_getParent()).toBe(null); }); - it('getChildren() works as intended', () => { + it('DO_NOT_USE_getChildren() works as intended', () => { const TestScope = React.unstable_createScope(); const TestScope2 = React.unstable_createScope(); const refA = React.createRef(); @@ -291,13 +291,13 @@ describe('ReactScope', () => { } ReactDOM.render(, container); - const dChildren = refD.current.getChildren(); + const dChildren = refD.current.DO_NOT_USE_getChildren(); expect(dChildren).toBe(null); - const cChildren = refC.current.getChildren(); + const cChildren = refC.current.DO_NOT_USE_getChildren(); expect(cChildren).toBe(null); - const bChildren = refB.current.getChildren(); + const bChildren = refB.current.DO_NOT_USE_getChildren(); expect(bChildren).toEqual([refD.current]); - const aChildren = refA.current.getChildren(); + const aChildren = refA.current.DO_NOT_USE_getChildren(); expect(aChildren).toEqual([refC.current]); }); @@ -328,7 +328,7 @@ describe('ReactScope', () => { container.innerHTML = html; ReactDOM.hydrate(, container); const testScopeQuery = (type, props) => true; - const nodes = scopeRef.current.queryAllNodes(testScopeQuery); + const nodes = scopeRef.current.DO_NOT_USE_queryAllNodes(testScopeQuery); expect(nodes).toEqual([divRef.current, spanRef.current, aRef.current]); }); @@ -373,6 +373,34 @@ describe('ReactScope', () => { target.keydown({key: 'Q'}); expect(onKeyDown).toHaveBeenCalledTimes(1); }); + + it('getChildContextValues() works as intended', () => { + const TestContext = React.createContext(); + const TestScope = React.unstable_createScope(); + const scopeRef = React.createRef(); + + function Test({toggle}) { + return toggle ? ( + + + + ) : ( + + + + + ); + } + + ReactDOM.render(, container); + let nodes = scopeRef.current.getChildContextValues(TestContext); + expect(nodes).toEqual([1]); + ReactDOM.render(, container); + nodes = scopeRef.current.getChildContextValues(TestContext); + expect(nodes).toEqual([1, 2]); + ReactDOM.render(null, container); + expect(scopeRef.current).toBe(null); + }); }); describe('ReactTestRenderer', () => { @@ -382,7 +410,7 @@ describe('ReactScope', () => { ReactTestRenderer = require('react-test-renderer'); }); - it('queryAllNodes() works as intended', () => { + it('DO_NOT_USE_queryAllNodes() works as intended', () => { const testScopeQuery = (type, props) => true; const TestScope = React.unstable_createScope(); const scopeRef = React.createRef(); @@ -411,14 +439,14 @@ describe('ReactScope', () => { return element; }, }); - let nodes = scopeRef.current.queryAllNodes(testScopeQuery); + let nodes = scopeRef.current.DO_NOT_USE_queryAllNodes(testScopeQuery); expect(nodes).toEqual([divRef.current, spanRef.current, aRef.current]); renderer.update(); - nodes = scopeRef.current.queryAllNodes(testScopeQuery); + nodes = scopeRef.current.DO_NOT_USE_queryAllNodes(testScopeQuery); expect(nodes).toEqual([aRef.current, divRef.current, spanRef.current]); }); - it('queryFirstNode() works as intended', () => { + it('DO_NOT_USE_queryFirstNode() works as intended', () => { const testScopeQuery = (type, props) => true; const TestScope = React.unstable_createScope(); const scopeRef = React.createRef(); @@ -447,10 +475,10 @@ describe('ReactScope', () => { return element; }, }); - let node = scopeRef.current.queryFirstNode(testScopeQuery); + let node = scopeRef.current.DO_NOT_USE_queryFirstNode(testScopeQuery); expect(node).toEqual(divRef.current); renderer.update(); - node = scopeRef.current.queryFirstNode(testScopeQuery); + node = scopeRef.current.DO_NOT_USE_queryFirstNode(testScopeQuery); expect(node).toEqual(aRef.current); }); @@ -507,7 +535,7 @@ describe('ReactScope', () => { expect(scopeRef.current.containsNode(emRef.current)).toBe(false); }); - it('mixed getParent() and queryAllNodes() works as intended', () => { + it('mixed DO_NOT_USE_getParent() and DO_NOT_USE_queryAllNodes() works as intended', () => { const testScopeQuery = (type, props) => true; const TestScope = React.unstable_createScope(); const TestScope2 = React.unstable_createScope(); @@ -547,26 +575,26 @@ describe('ReactScope', () => { return element; }, }); - const dParent = refD.current.getParent(); + const dParent = refD.current.DO_NOT_USE_getParent(); expect(dParent).not.toBe(null); - expect(dParent.queryAllNodes(testScopeQuery)).toEqual([ + expect(dParent.DO_NOT_USE_queryAllNodes(testScopeQuery)).toEqual([ divA.current, spanB.current, divB.current, ]); - const cParent = refC.current.getParent(); + const cParent = refC.current.DO_NOT_USE_getParent(); expect(cParent).not.toBe(null); - expect(cParent.queryAllNodes(testScopeQuery)).toEqual([ + expect(cParent.DO_NOT_USE_queryAllNodes(testScopeQuery)).toEqual([ spanA.current, divA.current, spanB.current, divB.current, ]); - expect(refB.current.getParent()).toBe(null); - expect(refA.current.getParent()).toBe(null); + expect(refB.current.DO_NOT_USE_getParent()).toBe(null); + expect(refA.current.DO_NOT_USE_getParent()).toBe(null); }); - it('getChildren() works as intended', () => { + it('DO_NOT_USE_getChildren() works as intended', () => { const TestScope = React.unstable_createScope(); const TestScope2 = React.unstable_createScope(); const refA = React.createRef(); @@ -605,13 +633,13 @@ describe('ReactScope', () => { return element; }, }); - const dChildren = refD.current.getChildren(); + const dChildren = refD.current.DO_NOT_USE_getChildren(); expect(dChildren).toBe(null); - const cChildren = refC.current.getChildren(); + const cChildren = refC.current.DO_NOT_USE_getChildren(); expect(cChildren).toBe(null); - const bChildren = refB.current.getChildren(); + const bChildren = refB.current.DO_NOT_USE_getChildren(); expect(bChildren).toEqual([refD.current]); - const aChildren = refA.current.getChildren(); + const aChildren = refA.current.DO_NOT_USE_getChildren(); expect(aChildren).toEqual([refC.current]); }); }); diff --git a/packages/shared/ReactTypes.js b/packages/shared/ReactTypes.js index e97e582339349..18508fb3fcb1e 100644 --- a/packages/shared/ReactTypes.js +++ b/packages/shared/ReactTypes.js @@ -171,17 +171,18 @@ export type ReactScope = {| |}; export type ReactScopeMethods = {| - getChildren(): null | Array, - getChildrenFromRoot(): null | Array, - getParent(): null | ReactScopeMethods, - getProps(): Object, - queryAllNodes( + DO_NOT_USE_getChildren(): null | Array, + DO_NOT_USE_getChildrenFromRoot(): null | Array, + DO_NOT_USE_getParent(): null | ReactScopeMethods, + DO_NOT_USE_getProps(): Object, + DO_NOT_USE_queryAllNodes( (type: string | Object, props: Object, instance: Object) => boolean, ): null | Array, - queryFirstNode( + DO_NOT_USE_queryFirstNode( (type: string | Object, props: Object, instance: Object) => boolean, ): null | Object, containsNode(Object): boolean, + getChildContextValues: (context: ReactContext) => Array, |}; export type ReactScopeInstance = {|