Revert "Disallow reading context during useMemo etc" (#14651)

* Revert "Add test coverage for readContext() on the server (#14649)"

This reverts commit fe2ecd276e.

* Revert "Warn about incorrect use of useImperativeHandle() (#14647)"

This reverts commit 8f45a7fdc4.

* Revert "Disallow reading context during useMemo etc (#14648)"

This reverts commit 1fcbd22431.
This commit is contained in:
Dan Abramov 2019-01-21 20:28:36 +00:00 committed by GitHub
parent fe2ecd276e
commit 5fce6488ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 12 additions and 110 deletions

View File

@ -20,6 +20,7 @@ import {
import ReactStrictModeWarnings from './ReactStrictModeWarnings';
import {isMounted} from 'react-reconciler/reflection';
import {get as getInstance, set as setInstance} from 'shared/ReactInstanceMap';
import ReactSharedInternals from 'shared/ReactSharedInternals';
import shallowEqual from 'shared/shallowEqual';
import getComponentName from 'shared/getComponentName';
import invariant from 'shared/invariant';
@ -47,7 +48,6 @@ import {
hasContextChanged,
emptyContextObject,
} from './ReactFiberContext';
import {readContext} from './ReactFiberNewContext';
import {
requestCurrentTime,
computeExpirationForFiber,
@ -55,6 +55,13 @@ import {
flushPassiveEffects,
} from './ReactFiberScheduler';
const ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
function readContext(contextType: any): any {
const dispatcher = ReactCurrentDispatcher.current;
return dispatcher.readContext(contextType);
}
const fakeInternalInstance = {};
const isArray = Array.isArray;

View File

@ -7,8 +7,8 @@
* @flow
*/
import {readContext} from './ReactFiberNewContext';
import {
readContext,
useCallback,
useContext,
useEffect,

View File

@ -14,7 +14,7 @@ import type {HookEffectTag} from './ReactHookEffectTags';
import {NoWork} from './ReactFiberExpirationTime';
import {enableHooks} from 'shared/ReactFeatureFlags';
import {readContext as readContextWithoutCheck} from './ReactFiberNewContext';
import {readContext} from './ReactFiberNewContext';
import {
Update as UpdateEffect,
Passive as PassiveEffect,
@ -284,7 +284,7 @@ export function resetHooks(): void {
// This is used to reset the state of this module when a component throws.
// It's also called inside mountIndeterminateComponent if we determine the
// component is a module-style component, and also in readContext() above.
// component is a module-style component.
renderExpirationTime = NoWork;
currentlyRenderingFiber = null;
@ -394,7 +394,7 @@ export function useContext<T>(
// Ensure we're in a function component (class components support only the
// .unstable_read() form)
resolveCurrentlyRenderingFiber();
return readContextWithoutCheck(context, observedBits);
return readContext(context, observedBits);
}
export function useState<S>(
@ -785,29 +785,6 @@ export function useMemo<T>(
return nextValue;
}
export function readContext<T>(
context: ReactContext<T>,
observedBits: void | number | boolean,
): T {
// Forbid reading context inside Hooks.
// The outer check tells us whether we're inside a Hook like useMemo().
// However, it would also be true if we're rendering a class.
if (currentlyRenderingFiber === null) {
// The inner check tells us we're currently in renderWithHooks() phase
// rather than, for example, in a class or a context consumer.
// Then we know it should be an error.
if (renderExpirationTime !== NoWork) {
invariant(
false,
'Context can only be read inside the body of a component. ' +
'If you read context inside a Hook like useMemo or useReducer, ' +
'move the call directly into the component body.',
);
}
}
return readContextWithoutCheck(context, observedBits);
}
function dispatchAction<S, A>(
fiber: Fiber,
queue: UpdateQueue<S, A>,

View File

@ -672,88 +672,6 @@ describe('ReactHooks', () => {
expect(root.toJSON()).toEqual('123');
});
it('throws when reading context inside useMemo', () => {
const {useMemo, createContext} = React;
const ReactCurrentDispatcher =
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
.ReactCurrentDispatcher;
const ThemeContext = createContext('light');
function App() {
return useMemo(() => {
return ReactCurrentDispatcher.current.readContext(ThemeContext);
}, []);
}
expect(() => ReactTestRenderer.create(<App />)).toThrow(
'Context can only be read inside the body of a component',
);
});
it('throws when reading context inside useEffect', () => {
const {useEffect, createContext} = React;
const ReactCurrentDispatcher =
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
.ReactCurrentDispatcher;
const ThemeContext = createContext('light');
function App() {
useEffect(() => {
ReactCurrentDispatcher.current.readContext(ThemeContext);
});
return null;
}
const root = ReactTestRenderer.create(<App />);
expect(() => root.update(<App />)).toThrow(
// The exact message doesn't matter, just make sure we don't allow this
"Cannot read property 'readContext' of null",
);
});
it('throws when reading context inside useLayoutEffect', () => {
const {useLayoutEffect, createContext} = React;
const ReactCurrentDispatcher =
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
.ReactCurrentDispatcher;
const ThemeContext = createContext('light');
function App() {
useLayoutEffect(() => {
ReactCurrentDispatcher.current.readContext(ThemeContext);
});
return null;
}
expect(() => ReactTestRenderer.create(<App />)).toThrow(
// The exact message doesn't matter, just make sure we don't allow this
"Cannot read property 'readContext' of null",
);
});
it('throws when reading context inside useReducer', () => {
const {useReducer, createContext} = React;
const ReactCurrentDispatcher =
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
.ReactCurrentDispatcher;
const ThemeContext = createContext('light');
function App() {
useReducer(
() => {
ReactCurrentDispatcher.current.readContext(ThemeContext);
},
null,
{},
);
return null;
}
expect(() => ReactTestRenderer.create(<App />)).toThrow(
'Context can only be read inside the body of a component.',
);
});
it('throws when calling hooks inside useReducer', () => {
const {useReducer, useRef} = React;
function App() {