Revert "Disallow reading context during useMemo etc" (#14651)
* Revert "Add test coverage for readContext() on the server (#14649)" This reverts commit fe2ecd276e9b9e57a49ddf2d86ff01677b69b493. * Revert "Warn about incorrect use of useImperativeHandle() (#14647)" This reverts commit 8f45a7fdc469c6d88ca5ca105095b03dd4e862e1. * Revert "Disallow reading context during useMemo etc (#14648)" This reverts commit 1fcbd22431d97e404c1f684744dc543b6c22b076.
Dan Abramov committed
Jan 21, 2019 at 20:28 UTC
5fce6488ce1dc97e31515a47ff409d32ab722d65
4 files changed
+12
-110
packages/react-reconciler/src/ReactFiberClassComponent.js
+8
-1
@@ -20,6 +20,7 @@ import {
20
import ReactStrictModeWarnings from './ReactStrictModeWarnings';
21
import {isMounted} from 'react-reconciler/reflection';
22
import {get as getInstance, set as setInstance} from 'shared/ReactInstanceMap';
23
+import ReactSharedInternals from 'shared/ReactSharedInternals';
24
import shallowEqual from 'shared/shallowEqual';
25
import getComponentName from 'shared/getComponentName';
26
import invariant from 'shared/invariant';
@@ -47,7 +48,6 @@ import {
48
hasContextChanged,
49
emptyContextObject,
50
} from './ReactFiberContext';
50
-import {readContext} from './ReactFiberNewContext';
51
import {
52
requestCurrentTime,
53
computeExpirationForFiber,
@@ -55,6 +55,13 @@ import {
55
flushPassiveEffects,
56
} from './ReactFiberScheduler';
57
58
+const ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
59
+
60
+function readContext(contextType: any): any {
61
+ const dispatcher = ReactCurrentDispatcher.current;
62
+ return dispatcher.readContext(contextType);
63
+}
64
+
65
const fakeInternalInstance = {};
66
const isArray = Array.isArray;
67
packages/react-reconciler/src/ReactFiberDispatcher.js
+1
-1
@@ -7,8 +7,8 @@
7
* @flow
8
*/
9
10
+import {readContext} from './ReactFiberNewContext';
11
import {
11
- readContext,
12
useCallback,
13
useContext,
14
useEffect,
packages/react-reconciler/src/ReactFiberHooks.js
+3
-26
@@ -14,7 +14,7 @@ import type {HookEffectTag} from './ReactHookEffectTags';
14
15
import {NoWork} from './ReactFiberExpirationTime';
16
import {enableHooks} from 'shared/ReactFeatureFlags';
17
-import {readContext as readContextWithoutCheck} from './ReactFiberNewContext';
17
+import {readContext} from './ReactFiberNewContext';
18
import {
19
Update as UpdateEffect,
20
Passive as PassiveEffect,
@@ -284,7 +284,7 @@ export function resetHooks(): void {
284
285
// This is used to reset the state of this module when a component throws.
286
// 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.
288
renderExpirationTime = NoWork;
289
currentlyRenderingFiber = null;
290
@@ -394,7 +394,7 @@ export function useContext<T>(
394
// Ensure we're in a function component (class components support only the
395
// .unstable_read() form)
396
resolveCurrentlyRenderingFiber();
397
- return readContextWithoutCheck(context, observedBits);
397
+ return readContext(context, observedBits);
398
}
399
400
export function useState<S>(
@@ -785,29 +785,6 @@ export function useMemo<T>(
785
return nextValue;
786
}
787
788
-export function readContext<T>(
789
- context: ReactContext<T>,
790
- observedBits: void | number | boolean,
791
-): T {
792
- // Forbid reading context inside Hooks.
793
- // The outer check tells us whether we're inside a Hook like useMemo().
794
- // However, it would also be true if we're rendering a class.
795
- if (currentlyRenderingFiber === null) {
796
- // The inner check tells us we're currently in renderWithHooks() phase
797
- // rather than, for example, in a class or a context consumer.
798
- // Then we know it should be an error.
799
- if (renderExpirationTime !== NoWork) {
800
- invariant(
801
- false,
802
- 'Context can only be read inside the body of a component. ' +
803
- 'If you read context inside a Hook like useMemo or useReducer, ' +
804
- 'move the call directly into the component body.',
805
- );
806
- }
807
- }
808
- return readContextWithoutCheck(context, observedBits);
809
-}
810
-
788
function dispatchAction<S, A>(
789
fiber: Fiber,
790
queue: UpdateQueue<S, A>,
packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js
-82
@@ -672,88 +672,6 @@ describe('ReactHooks', () => {
672
expect(root.toJSON()).toEqual('123');
673
});
674
675
- it('throws when reading context inside useMemo', () => {
676
- const {useMemo, 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
- return useMemo(() => {
684
- return ReactCurrentDispatcher.current.readContext(ThemeContext);
685
- }, []);
686
- }
687
-
688
- expect(() => ReactTestRenderer.create(<App />)).toThrow(
689
- 'Context can only be read inside the body of a component',
690
- );
691
- });
692
-
693
- it('throws when reading context inside useEffect', () => {
694
- const {useEffect, createContext} = React;
695
- const ReactCurrentDispatcher =
696
- React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
697
- .ReactCurrentDispatcher;
698
-
699
- const ThemeContext = createContext('light');
700
- function App() {
701
- useEffect(() => {
702
- ReactCurrentDispatcher.current.readContext(ThemeContext);
703
- });
704
- return null;
705
- }
706
-
707
- const root = ReactTestRenderer.create(<App />);
708
- expect(() => root.update(<App />)).toThrow(
709
- // The exact message doesn't matter, just make sure we don't allow this
710
- "Cannot read property 'readContext' of null",
711
- );
712
- });
713
-
714
- it('throws when reading context inside useLayoutEffect', () => {
715
- const {useLayoutEffect, createContext} = React;
716
- const ReactCurrentDispatcher =
717
- React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
718
- .ReactCurrentDispatcher;
719
-
720
- const ThemeContext = createContext('light');
721
- function App() {
722
- useLayoutEffect(() => {
723
- ReactCurrentDispatcher.current.readContext(ThemeContext);
724
- });
725
- return null;
726
- }
727
-
728
- expect(() => ReactTestRenderer.create(<App />)).toThrow(
729
- // The exact message doesn't matter, just make sure we don't allow this
730
- "Cannot read property 'readContext' of null",
731
- );
732
- });
733
-
734
- it('throws when reading context inside useReducer', () => {
735
- const {useReducer, createContext} = React;
736
- const ReactCurrentDispatcher =
737
- React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
738
- .ReactCurrentDispatcher;
739
-
740
- const ThemeContext = createContext('light');
741
- function App() {
742
- useReducer(
743
- () => {
744
- ReactCurrentDispatcher.current.readContext(ThemeContext);
745
- },
746
- null,
747
- {},
748
- );
749
- return null;
750
- }
751
-
752
- expect(() => ReactTestRenderer.create(<App />)).toThrow(
753
- 'Context can only be read inside the body of a component.',
754
- );
755
- });
756
-
675
it('throws when calling hooks inside useReducer', () => {
676
const {useReducer, useRef} = React;
677
function App() {