diff --git a/packages/react-devtools-shared/src/devtools/views/Components/Element.js b/packages/react-devtools-shared/src/devtools/views/Components/Element.js index 7854f4c99b3ae..71e0ebfbe9cbe 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/Element.js +++ b/packages/react-devtools-shared/src/devtools/views/Components/Element.js @@ -23,6 +23,7 @@ import type {Element as ElementType} from 'react-devtools-shared/src/frontend/ty import styles from './Element.css'; import Icon from '../Icon'; +import {useChangeOwnerAction} from './OwnersListContext'; type Props = { data: ItemData, @@ -66,9 +67,10 @@ export default function Element({data, index, style}: Props): React.Node { warningCount: number, }>(errorsAndWarningsSubscription); + const changeOwnerAction = useChangeOwnerAction(); const handleDoubleClick = () => { if (id !== null) { - dispatch({type: 'SELECT_OWNER', payload: id}); + changeOwnerAction(id); } }; diff --git a/packages/react-devtools-shared/src/devtools/views/Components/OwnersListContext.js b/packages/react-devtools-shared/src/devtools/views/Components/OwnersListContext.js index f88bc7e9724be..060a5711626e8 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/OwnersListContext.js +++ b/packages/react-devtools-shared/src/devtools/views/Components/OwnersListContext.js @@ -13,7 +13,7 @@ import * as React from 'react'; import {createContext, useCallback, useContext, useEffect} from 'react'; import {createResource} from '../../cache'; import {BridgeContext, StoreContext} from '../context'; -import {TreeStateContext} from './TreeContext'; +import {TreeDispatcherContext, TreeStateContext} from './TreeContext'; import {backendToFrontendSerializedElementMapper} from 'react-devtools-shared/src/utils'; import type {OwnersList} from 'react-devtools-shared/src/backend/types'; @@ -70,6 +70,43 @@ type Props = { children: React$Node, }; +function useChangeOwnerAction(): (nextOwnerID: number) => void { + const bridge = useContext(BridgeContext); + const store = useContext(StoreContext); + const treeAction = useContext(TreeDispatcherContext); + + return useCallback( + function changeOwnerAction(nextOwnerID: number) { + treeAction({type: 'SELECT_OWNER', payload: nextOwnerID}); + + const element = store.getElementByID(nextOwnerID); + if (element !== null) { + if (!inProgressRequests.has(element)) { + let resolveFn: + | ResolveFn + | (( + result: + | Promise> + | Array, + ) => void) = ((null: any): ResolveFn); + const promise = new Promise(resolve => { + resolveFn = resolve; + }); + + // $FlowFixMe[incompatible-call] found when upgrading Flow + inProgressRequests.set(element, {promise, resolveFn}); + } + + const rendererID = store.getRendererIDForElement(nextOwnerID); + if (rendererID !== null) { + bridge.send('getOwnersList', {id: nextOwnerID, rendererID}); + } + } + }, + [bridge, store], + ); +} + function OwnersListContextController({children}: Props): React.Node { const bridge = useContext(BridgeContext); const store = useContext(StoreContext); @@ -95,8 +132,6 @@ function OwnersListContextController({children}: Props): React.Node { if (element !== null) { const request = inProgressRequests.get(element); if (request != null) { - inProgressRequests.delete(element); - request.resolveFn( ownersList.owners === null ? null @@ -129,4 +164,4 @@ function OwnersListContextController({children}: Props): React.Node { ); } -export {OwnersListContext, OwnersListContextController}; +export {OwnersListContext, OwnersListContextController, useChangeOwnerAction}; diff --git a/packages/react-devtools-shared/src/devtools/views/Components/OwnersStack.js b/packages/react-devtools-shared/src/devtools/views/Components/OwnersStack.js index 0486b55c69db4..0fa5c0910bb6e 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/OwnersStack.js +++ b/packages/react-devtools-shared/src/devtools/views/Components/OwnersStack.js @@ -20,7 +20,7 @@ import Button from '../Button'; import ButtonIcon from '../ButtonIcon'; import Toggle from '../Toggle'; import ElementBadges from './ElementBadges'; -import {OwnersListContext} from './OwnersListContext'; +import {OwnersListContext, useChangeOwnerAction} from './OwnersListContext'; import {TreeDispatcherContext, TreeStateContext} from './TreeContext'; import {useIsOverflowing} from '../hooks'; import {StoreContext} from '../context'; @@ -81,6 +81,7 @@ export default function OwnerStack(): React.Node { const read = useContext(OwnersListContext); const {ownerID} = useContext(TreeStateContext); const treeDispatch = useContext(TreeDispatcherContext); + const changeOwnerAction = useChangeOwnerAction(); const [state, dispatch] = useReducer(dialogReducer, { ownerID: null, @@ -116,7 +117,7 @@ export default function OwnerStack(): React.Node { type: 'UPDATE_SELECTED_INDEX', selectedIndex: index >= 0 ? index : 0, }); - treeDispatch({type: 'SELECT_OWNER', payload: owner.id}); + changeOwnerAction(owner.id); } else { dispatch({ type: 'UPDATE_SELECTED_INDEX', diff --git a/packages/react-devtools-shared/src/devtools/views/Components/Tree.js b/packages/react-devtools-shared/src/devtools/views/Components/Tree.js index d0fc0d924cd17..1ba61c52dd1a4 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/Tree.js +++ b/packages/react-devtools-shared/src/devtools/views/Components/Tree.js @@ -38,6 +38,7 @@ import ButtonIcon from '../ButtonIcon'; import Button from '../Button'; import {logEvent} from 'react-devtools-shared/src/Logger'; import {useExtensionComponentsPanelVisibility} from 'react-devtools-shared/src/frontend/hooks/useExtensionComponentsPanelVisibility'; +import {useChangeOwnerAction} from './OwnersListContext'; // Never indent more than this number of pixels (even if we have the room). const DEFAULT_INDENTATION_SIZE = 12; @@ -217,13 +218,14 @@ export default function Tree(): React.Node { const handleBlur = useCallback(() => setTreeFocused(false), []); const handleFocus = useCallback(() => setTreeFocused(true), []); + const changeOwnerAction = useChangeOwnerAction(); const handleKeyPress = useCallback( (event: $FlowFixMe) => { switch (event.key) { case 'Enter': case ' ': if (inspectedElementID !== null) { - dispatch({type: 'SELECT_OWNER', payload: inspectedElementID}); + changeOwnerAction(inspectedElementID); } break; default: diff --git a/packages/react-devtools-shared/src/devtools/views/Components/TreeContext.js b/packages/react-devtools-shared/src/devtools/views/Components/TreeContext.js index fa1d619a93c28..46c76462d09d4 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/TreeContext.js +++ b/packages/react-devtools-shared/src/devtools/views/Components/TreeContext.js @@ -148,6 +148,7 @@ const TreeStateContext: ReactContext = createContext(((null: any): StateContext)); TreeStateContext.displayName = 'TreeStateContext'; +// TODO: `dispatch` is an Action and should be named accordingly. const TreeDispatcherContext: ReactContext = createContext(((null: any): DispatcherContext)); TreeDispatcherContext.displayName = 'TreeDispatcherContext'; @@ -953,7 +954,7 @@ function TreeContextController({ return ( - + {children}