Skip to content

Commit

Permalink
DevTools: Fix inspecting components with multiple reads of the same C…
Browse files Browse the repository at this point in the history
…ontext in React 17
  • Loading branch information
eps1lon committed May 2, 2024
1 parent 4508873 commit 1062e3b
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 8 deletions.
21 changes: 13 additions & 8 deletions packages/react-debug-tools/src/ReactDebugHooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,15 +177,20 @@ function readContext<T>(context: ReactContext<T>): T {
);
}

let value: T;
// For now we don't expose readContext usage in the hooks debugging info.
const value = hasOwnProperty.call(currentContextDependency, 'memoizedValue')
? // $FlowFixMe[incompatible-use] Flow thinks `hasOwnProperty` mutates `currentContextDependency`
((currentContextDependency.memoizedValue: any): T)
: // Before React 18, we did not have `memoizedValue` so we rely on `setupContexts` in those versions.
// $FlowFixMe[incompatible-use] Flow thinks `hasOwnProperty` mutates `currentContextDependency`
((currentContextDependency.context._currentValue: any): T);
// $FlowFixMe[incompatible-use] Flow thinks `hasOwnProperty` mutates `currentContextDependency`
currentContextDependency = currentContextDependency.next;
if (hasOwnProperty.call(currentContextDependency, 'memoizedValue')) {
// $FlowFixMe[incompatible-use] Flow thinks `hasOwnProperty` mutates `currentContextDependency`
value = ((currentContextDependency.memoizedValue: any): T);

// $FlowFixMe[incompatible-use] Flow thinks `hasOwnProperty` mutates `currentContextDependency`
currentContextDependency = currentContextDependency.next;
} else {
// Before React 18, we did not have `memoizedValue` so we rely on `setupContexts` in those versions.
// Multiple reads of the same context were also only tracked as a single dependency.
// We just give up on advancing context dependencies and solely rely on `setupContexts`.
value = context._currentValue;
}

return value;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -833,6 +833,44 @@ describe('ReactHooksInspectionIntegration', () => {
`);
});

it('should inspect the value of the current provider in useContext reading the same context multiple times', async () => {
const ContextA = React.createContext('default A');
const ContextB = React.createContext('default B');
function Foo(props) {
React.useContext(ContextA);
React.useContext(ContextA);
React.useContext(ContextB);
React.useContext(ContextB);
React.useContext(ContextA);
React.useContext(ContextB);
React.useContext(ContextB);
React.useContext(ContextB);
return null;
}
let renderer;
await act(() => {
renderer = ReactTestRenderer.create(
<ContextA.Provider value="contextual A">
<Foo prop="prop" />
</ContextA.Provider>,
{unstable_isConcurrent: true},
);
});
const childFiber = renderer.root.findByType(Foo)._currentFiber();
const tree = ReactDebugTools.inspectHooksOfFiber(childFiber);

expect(normalizeSourceLoc(tree)).toEqual([
expect.objectContaining({value: 'contextual A'}),
expect.objectContaining({value: 'contextual A'}),
expect.objectContaining({value: 'default B'}),
expect.objectContaining({value: 'default B'}),
expect.objectContaining({value: 'contextual A'}),
expect.objectContaining({value: 'default B'}),
expect.objectContaining({value: 'default B'}),
expect.objectContaining({value: 'default B'}),
]);
});

it('should inspect forwardRef', async () => {
const obj = function () {};
const Foo = React.forwardRef(function (props, ref) {
Expand Down

0 comments on commit 1062e3b

Please sign in to comment.