Skip to content

Commit 4955d0d

Browse files
author
Sebastian Silbermann
committed
DevTools: Add support for use(Context)
1 parent bfdc12c commit 4955d0d

File tree

3 files changed

+76
-7
lines changed

3 files changed

+76
-7
lines changed

packages/react-debug-tools/src/ReactDebugHooks.js

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import type {
1212
ReactContext,
1313
ReactProviderType,
1414
StartTransitionOptions,
15+
Usable,
1516
} from 'shared/ReactTypes';
1617
import type {
1718
Fiber,
@@ -27,7 +28,11 @@ import {
2728
ContextProvider,
2829
ForwardRef,
2930
} from 'react-reconciler/src/ReactWorkTags';
30-
import {REACT_MEMO_CACHE_SENTINEL} from 'shared/ReactSymbols';
31+
import {
32+
REACT_MEMO_CACHE_SENTINEL,
33+
REACT_CONTEXT_TYPE,
34+
REACT_SERVER_CONTEXT_TYPE,
35+
} from 'shared/ReactSymbols';
3136

3237
type CurrentDispatcherRef = typeof ReactSharedInternals.ReactCurrentDispatcher;
3338

@@ -118,11 +123,33 @@ function readContext<T>(context: ReactContext<T>): T {
118123
return context._currentValue;
119124
}
120125

121-
function use<T>(): T {
122-
// TODO: What should this do if it receives an unresolved promise?
123-
throw new Error(
124-
'Support for `use` not yet implemented in react-debug-tools.',
125-
);
126+
function use<T>(usable: Usable<T>): T {
127+
if (usable !== null && typeof usable === 'object') {
128+
// $FlowFixMe[method-unbinding]
129+
if (typeof usable.then === 'function') {
130+
// TODO: What should this do if it receives an unresolved promise?
131+
throw new Error(
132+
'Support for `use(Promise)` not yet implemented in react-debug-tools.',
133+
);
134+
} else if (
135+
usable.$$typeof === REACT_CONTEXT_TYPE ||
136+
usable.$$typeof === REACT_SERVER_CONTEXT_TYPE
137+
) {
138+
const context: ReactContext<T> = (usable: any);
139+
const value = readContext(context);
140+
141+
hookLog.push({
142+
primitive: 'Use',
143+
stackError: new Error(),
144+
value,
145+
});
146+
147+
return value;
148+
}
149+
}
150+
151+
// eslint-disable-next-line react-internal/safe-string-coercion
152+
throw new Error('An unsupported type was passed to use(): ' + String(usable));
126153
}
127154

128155
function useContext<T>(context: ReactContext<T>): T {
@@ -660,7 +687,9 @@ function buildTree(
660687
// For now, the "id" of stateful hooks is just the stateful hook index.
661688
// Custom hooks have no ids, nor do non-stateful native hooks (e.g. Context, DebugValue).
662689
const id =
663-
primitive === 'Context' || primitive === 'DebugValue'
690+
primitive === 'Context' ||
691+
primitive === 'DebugValue' ||
692+
primitive === 'Use'
664693
? null
665694
: nativeHookID++;
666695

packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,6 +1108,44 @@ describe('ReactHooksInspectionIntegration', () => {
11081108
]);
11091109
});
11101110

1111+
it('should support use(Context) hook', () => {
1112+
const Context = React.createContext('default');
1113+
function Foo() {
1114+
const value = React.use(Context);
1115+
React.useMemo(() => 'memo', []);
1116+
React.useMemo(() => 'not used', []);
1117+
1118+
return value;
1119+
}
1120+
1121+
const renderer = ReactTestRenderer.create(<Foo />);
1122+
const childFiber = renderer.root.findByType(Foo)._currentFiber();
1123+
const tree = ReactDebugTools.inspectHooksOfFiber(childFiber);
1124+
expect(tree).toEqual([
1125+
{
1126+
id: null,
1127+
isStateEditable: false,
1128+
name: 'Use',
1129+
value: 'default',
1130+
subHooks: [],
1131+
},
1132+
{
1133+
id: 0,
1134+
isStateEditable: false,
1135+
name: 'Memo',
1136+
value: 'memo',
1137+
subHooks: [],
1138+
},
1139+
{
1140+
id: 1,
1141+
isStateEditable: false,
1142+
name: 'Memo',
1143+
value: 'not used',
1144+
subHooks: [],
1145+
},
1146+
]);
1147+
});
1148+
11111149
// @gate enableAsyncActions
11121150
it('should support useOptimistic hook', () => {
11131151
const useOptimistic = React.useOptimistic;

packages/react-devtools-shell/src/app/InspectableElements/CustomHooks.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
useEffect,
2020
useOptimistic,
2121
useState,
22+
use,
2223
} from 'react';
2324
import {useFormState} from 'react-dom';
2425

@@ -76,6 +77,7 @@ function FunctionWithHooks(props: any, ref: React$Ref<any>) {
7677
// eslint-disable-next-line no-unused-vars
7778
const contextValueA = useContext(ContextA);
7879
useOptimistic<number, mixed>(1);
80+
use(ContextA);
7981

8082
// eslint-disable-next-line no-unused-vars
8183
const [_, __] = useState(object);

0 commit comments

Comments
 (0)