Skip to content

Commit 2f6d5f4

Browse files
authored
Revert "Disallow reading context during useMemo etc (#14648)"
This reverts commit 1fcbd22.
1 parent 3c24113 commit 2f6d5f4

File tree

4 files changed

+12
-110
lines changed

4 files changed

+12
-110
lines changed

packages/react-reconciler/src/ReactFiberClassComponent.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
import ReactStrictModeWarnings from './ReactStrictModeWarnings';
2121
import {isMounted} from 'react-reconciler/reflection';
2222
import {get as getInstance, set as setInstance} from 'shared/ReactInstanceMap';
23+
import ReactSharedInternals from 'shared/ReactSharedInternals';
2324
import shallowEqual from 'shared/shallowEqual';
2425
import getComponentName from 'shared/getComponentName';
2526
import invariant from 'shared/invariant';
@@ -47,14 +48,20 @@ import {
4748
hasContextChanged,
4849
emptyContextObject,
4950
} from './ReactFiberContext';
50-
import {readContext} from './ReactFiberNewContext';
5151
import {
5252
requestCurrentTime,
5353
computeExpirationForFiber,
5454
scheduleWork,
5555
flushPassiveEffects,
5656
} from './ReactFiberScheduler';
5757

58+
const ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
59+
60+
function readContext(contextType: any): any {
61+
const dispatcher = ReactCurrentDispatcher.current;
62+
return dispatcher.readContext(contextType);
63+
}
64+
5865
const fakeInternalInstance = {};
5966
const isArray = Array.isArray;
6067

packages/react-reconciler/src/ReactFiberDispatcher.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
* @flow
88
*/
99

10+
import {readContext} from './ReactFiberNewContext';
1011
import {
11-
readContext,
1212
useCallback,
1313
useContext,
1414
useEffect,

packages/react-reconciler/src/ReactFiberHooks.js

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import type {HookEffectTag} from './ReactHookEffectTags';
1414

1515
import {NoWork} from './ReactFiberExpirationTime';
1616
import {enableHooks} from 'shared/ReactFeatureFlags';
17-
import {readContext as readContextWithoutCheck} from './ReactFiberNewContext';
17+
import {readContext} from './ReactFiberNewContext';
1818
import {
1919
Update as UpdateEffect,
2020
Passive as PassiveEffect,
@@ -284,7 +284,7 @@ export function resetHooks(): void {
284284

285285
// This is used to reset the state of this module when a component throws.
286286
// It's also called inside mountIndeterminateComponent if we determine the
287-
// component is a module-style component, and also in readContext() above.
287+
// component is a module-style component.
288288
renderExpirationTime = NoWork;
289289
currentlyRenderingFiber = null;
290290

@@ -394,7 +394,7 @@ export function useContext<T>(
394394
// Ensure we're in a function component (class components support only the
395395
// .unstable_read() form)
396396
resolveCurrentlyRenderingFiber();
397-
return readContextWithoutCheck(context, observedBits);
397+
return readContext(context, observedBits);
398398
}
399399

400400
export function useState<S>(
@@ -771,29 +771,6 @@ export function useMemo<T>(
771771
return nextValue;
772772
}
773773

774-
export function readContext<T>(
775-
context: ReactContext<T>,
776-
observedBits: void | number | boolean,
777-
): T {
778-
// Forbid reading context inside Hooks.
779-
// The outer check tells us whether we're inside a Hook like useMemo().
780-
// However, it would also be true if we're rendering a class.
781-
if (currentlyRenderingFiber === null) {
782-
// The inner check tells us we're currently in renderWithHooks() phase
783-
// rather than, for example, in a class or a context consumer.
784-
// Then we know it should be an error.
785-
if (renderExpirationTime !== NoWork) {
786-
invariant(
787-
false,
788-
'Context can only be read inside the body of a component. ' +
789-
'If you read context inside a Hook like useMemo or useReducer, ' +
790-
'move the call directly into the component body.',
791-
);
792-
}
793-
}
794-
return readContextWithoutCheck(context, observedBits);
795-
}
796-
797774
function dispatchAction<S, A>(
798775
fiber: Fiber,
799776
queue: UpdateQueue<S, A>,

packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js

Lines changed: 0 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -633,88 +633,6 @@ describe('ReactHooks', () => {
633633
expect(root.toJSON()).toEqual('123');
634634
});
635635

636-
it('throws when reading context inside useMemo', () => {
637-
const {useMemo, createContext} = React;
638-
const ReactCurrentDispatcher =
639-
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
640-
.ReactCurrentDispatcher;
641-
642-
const ThemeContext = createContext('light');
643-
function App() {
644-
return useMemo(() => {
645-
return ReactCurrentDispatcher.current.readContext(ThemeContext);
646-
}, []);
647-
}
648-
649-
expect(() => ReactTestRenderer.create(<App />)).toThrow(
650-
'Context can only be read inside the body of a component',
651-
);
652-
});
653-
654-
it('throws when reading context inside useEffect', () => {
655-
const {useEffect, createContext} = React;
656-
const ReactCurrentDispatcher =
657-
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
658-
.ReactCurrentDispatcher;
659-
660-
const ThemeContext = createContext('light');
661-
function App() {
662-
useEffect(() => {
663-
ReactCurrentDispatcher.current.readContext(ThemeContext);
664-
});
665-
return null;
666-
}
667-
668-
const root = ReactTestRenderer.create(<App />);
669-
expect(() => root.update(<App />)).toThrow(
670-
// The exact message doesn't matter, just make sure we don't allow this
671-
"Cannot read property 'readContext' of null",
672-
);
673-
});
674-
675-
it('throws when reading context inside useLayoutEffect', () => {
676-
const {useLayoutEffect, createContext} = React;
677-
const ReactCurrentDispatcher =
678-
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
679-
.ReactCurrentDispatcher;
680-
681-
const ThemeContext = createContext('light');
682-
function App() {
683-
useLayoutEffect(() => {
684-
ReactCurrentDispatcher.current.readContext(ThemeContext);
685-
});
686-
return null;
687-
}
688-
689-
expect(() => ReactTestRenderer.create(<App />)).toThrow(
690-
// The exact message doesn't matter, just make sure we don't allow this
691-
"Cannot read property 'readContext' of null",
692-
);
693-
});
694-
695-
it('throws when reading context inside useReducer', () => {
696-
const {useReducer, createContext} = React;
697-
const ReactCurrentDispatcher =
698-
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
699-
.ReactCurrentDispatcher;
700-
701-
const ThemeContext = createContext('light');
702-
function App() {
703-
useReducer(
704-
() => {
705-
ReactCurrentDispatcher.current.readContext(ThemeContext);
706-
},
707-
null,
708-
{},
709-
);
710-
return null;
711-
}
712-
713-
expect(() => ReactTestRenderer.create(<App />)).toThrow(
714-
'Context can only be read inside the body of a component.',
715-
);
716-
});
717-
718636
it('throws when calling hooks inside useReducer', () => {
719637
const {useReducer, useRef} = React;
720638
function App() {

0 commit comments

Comments
 (0)