Remove unstable_read() in favor of direct dispatcher call (#13861)
* Remove unstable_read() in favor of direct dispatcher call * This no longer throws immediately
Dan Abramov committed
Oct 16, 2018 at 14:58 UTC
7685b55d27c3932fd803230452cfd3d1ab076195
7 files changed
+41
-78
packages/react-reconciler/src/ReactFiberClassComponent.js
+13
-5
@@ -20,6 +20,7 @@ import {
20
import ReactStrictModeWarnings from './ReactStrictModeWarnings';
21
import {isMounted} from 'react-reconciler/reflection';
22
import * as ReactInstanceMap 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';
@@ -50,6 +51,13 @@ import {
51
scheduleWork,
52
} from './ReactFiberScheduler';
53
54
+const ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;
55
+
56
+function readContext(contextType: any): any {
57
+ const dispatcher = ReactCurrentOwner.currentDispatcher;
58
+ return dispatcher.readContext(contextType);
59
+}
60
+
61
const fakeInternalInstance = {};
62
const isArray = Array.isArray;
63
@@ -508,7 +516,7 @@ function constructClassInstance(
516
if (typeof contextType === 'object' && contextType !== null) {
517
if (__DEV__) {
518
if (
511
- typeof contextType.unstable_read !== 'function' &&
519
+ contextType.Consumer === undefined &&
520
!didWarnAboutInvalidateContextType.has(ctor)
521
) {
522
didWarnAboutInvalidateContextType.add(ctor);
@@ -522,7 +530,7 @@ function constructClassInstance(
530
}
531
}
532
525
- context = (contextType: any).unstable_read();
533
+ context = readContext((contextType: any));
534
} else {
535
unmaskedContext = getUnmaskedContext(workInProgress, ctor, true);
536
const contextTypes = ctor.contextTypes;
@@ -725,7 +733,7 @@ function mountClassInstance(
733
734
const contextType = ctor.contextType;
735
if (typeof contextType === 'object' && contextType !== null) {
728
- instance.context = (contextType: any).unstable_read();
736
+ instance.context = readContext(contextType);
737
} else {
738
const unmaskedContext = getUnmaskedContext(workInProgress, ctor, true);
739
instance.context = getMaskedContext(workInProgress, unmaskedContext);
@@ -833,7 +841,7 @@ function resumeMountClassInstance(
841
const contextType = ctor.contextType;
842
let nextContext;
843
if (typeof contextType === 'object' && contextType !== null) {
836
- nextContext = (contextType: any).unstable_read();
844
+ nextContext = readContext(contextType);
845
} else {
846
const nextLegacyUnmaskedContext = getUnmaskedContext(
847
workInProgress,
@@ -979,7 +987,7 @@ function updateClassInstance(
987
const contextType = ctor.contextType;
988
let nextContext;
989
if (typeof contextType === 'object' && contextType !== null) {
982
- nextContext = (contextType: any).unstable_read();
990
+ nextContext = readContext(contextType);
991
} else {
992
const nextUnmaskedContext = getUnmaskedContext(workInProgress, ctor, true);
993
nextContext = getMaskedContext(workInProgress, nextUnmaskedContext);
packages/react-reconciler/src/ReactFiberNewContext.js
+1
-1
@@ -302,7 +302,7 @@ export function readContext<T>(
302
if (lastContextDependency === null) {
303
invariant(
304
currentlyRenderingFiber !== null,
305
- 'Context.unstable_read(): Context can only be read while React is ' +
305
+ 'Context can only be read while React is ' +
306
'rendering, e.g. inside the render method or getDerivedStateFromProps.',
307
);
308
// This is the first dependency in the list
packages/react-reconciler/src/__tests__/ReactNewContext-test.internal.js
+16
-36
@@ -39,26 +39,33 @@ describe('ReactNewContext', () => {
39
return {type: 'span', children: [], prop};
40
}
41
42
+ function readContext(Context, observedBits) {
43
+ const dispatcher =
44
+ React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner
45
+ .currentDispatcher;
46
+ return dispatcher.readContext(Context, observedBits);
47
+ }
48
+
49
// We have several ways of reading from context. sharedContextTests runs
50
// a suite of tests for a given context consumer implementation.
51
sharedContextTests('Context.Consumer', Context => Context.Consumer);
52
sharedContextTests(
46
- 'Context.unstable_read inside function component',
53
+ 'readContext(Context) inside function component',
54
Context =>
55
function Consumer(props) {
56
const observedBits = props.unstable_observedBits;
50
- const contextValue = Context.unstable_read(observedBits);
57
+ const contextValue = readContext(Context, observedBits);
58
const render = props.children;
59
return render(contextValue);
60
},
61
);
62
sharedContextTests(
56
- 'Context.unstable_read inside class component',
63
+ 'readContext(Context) inside class component',
64
Context =>
65
class Consumer extends React.Component {
66
render() {
67
const observedBits = this.props.unstable_observedBits;
61
- const contextValue = Context.unstable_read(observedBits);
68
+ const contextValue = readContext(Context, observedBits);
69
const render = this.props.children;
70
return render(contextValue);
71
}
@@ -1192,7 +1199,7 @@ describe('ReactNewContext', () => {
1199
return (
1200
<FooContext.Consumer>
1201
{foo => {
1195
- const bar = BarContext.unstable_read();
1202
+ const bar = readContext(BarContext);
1203
return <Text text={`Foo: ${foo}, Bar: ${bar}`} />;
1204
}}
1205
</FooContext.Consumer>
@@ -1236,7 +1243,7 @@ describe('ReactNewContext', () => {
1243
});
1244
});
1245
1239
- describe('unstable_readContext', () => {
1246
+ describe('readContext', () => {
1247
it('can use the same context multiple times in the same function', () => {
1248
const Context = React.createContext({foo: 0, bar: 0, baz: 0}, (a, b) => {
1249
let result = 0;
@@ -1262,13 +1269,13 @@ describe('ReactNewContext', () => {
1269
}
1270
1271
function FooAndBar() {
1265
- const {foo} = Context.unstable_read(0b001);
1266
- const {bar} = Context.unstable_read(0b010);
1272
+ const {foo} = readContext(Context, 0b001);
1273
+ const {bar} = readContext(Context, 0b010);
1274
return <Text text={`Foo: ${foo}, Bar: ${bar}`} />;
1275
}
1276
1277
function Baz() {
1271
- const {baz} = Context.unstable_read(0b100);
1278
+ const {baz} = readContext(Context, 0b100);
1279
return <Text text={'Baz: ' + baz} />;
1280
}
1281
@@ -1631,33 +1638,6 @@ Context fuzz tester error! Copy and paste the following line into the test suite
1638
);
1639
});
1640
1634
- it('should warn with an error message when using Context.Consumer.unstable_read() DEV', () => {
1635
- const BarContext = React.createContext({value: 'bar-initial'});
1636
-
1637
- function Child() {
1638
- let value = BarContext.Consumer.unstable_read();
1639
- return <div actual={value} expected="bar-updated" />;
1640
- }
1641
-
1642
- function Component() {
1643
- return (
1644
- <React.Fragment>
1645
- <BarContext.Provider value={{value: 'bar-updated'}}>
1646
- <Child />
1647
- </BarContext.Provider>
1648
- </React.Fragment>
1649
- );
1650
- }
1651
-
1652
- expect(() => {
1653
- ReactNoop.render(<Component />);
1654
- ReactNoop.flush();
1655
- }).toWarnDev(
1656
- 'Calling Context.Consumer.unstable_read() is not supported and will be removed in ' +
1657
- 'a future major release. Did you mean to render Context.unstable_read() instead?',
1658
- );
1659
- });
1660
-
1641
it('should warn with an error message when using Context.Consumer.Provider DEV', () => {
1642
const BarContext = React.createContext({value: 'bar-initial'});
1643
packages/react-reconciler/src/__tests__/ReactPure-test.internal.js
+8
-1
@@ -90,8 +90,15 @@ describe('pure', () => {
90
91
const CountContext = React.createContext(0);
92
93
+ function readContext(Context) {
94
+ const dispatcher =
95
+ React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
96
+ .ReactCurrentOwner.currentDispatcher;
97
+ return dispatcher.readContext(Context);
98
+ }
99
+
100
function Counter(props) {
94
- const count = CountContext.unstable_read();
101
+ const count = readContext(CountContext);
102
return <Text text={`${props.label}: ${count}`} />;
103
}
104
Counter = pure(Counter);
packages/react/src/ReactContext.js
-31
@@ -11,25 +11,9 @@ import {REACT_PROVIDER_TYPE, REACT_CONTEXT_TYPE} from 'shared/ReactSymbols';
11
12
import type {ReactContext} from 'shared/ReactTypes';
13
14
-import invariant from 'shared/invariant';
14
import warningWithoutStack from 'shared/warningWithoutStack';
15
import warning from 'shared/warning';
16
18
-import ReactCurrentOwner from './ReactCurrentOwner';
19
-
20
-export function readContext<T>(
21
- context: ReactContext<T>,
22
- observedBits: void | number | boolean,
23
-): T {
24
- const dispatcher = ReactCurrentOwner.currentDispatcher;
25
- invariant(
26
- dispatcher !== null,
27
- 'Context.unstable_read(): Context can only be read while React is ' +
28
- 'rendering, e.g. inside the render method or getDerivedStateFromProps.',
29
- );
30
- return dispatcher.readContext(context, observedBits);
31
-}
32
-
17
export function createContext<T>(
18
defaultValue: T,
19
calculateChangedBits: ?(a: T, b: T) => number,
@@ -61,7 +45,6 @@ export function createContext<T>(
45
// These are circular
46
Provider: (null: any),
47
Consumer: (null: any),
64
- unstable_read: (null: any),
48
};
49
50
context.Provider = {
@@ -69,10 +52,7 @@ export function createContext<T>(
52
_context: context,
53
};
54
72
- context.unstable_read = readContext.bind(null, context);
73
-
55
let hasWarnedAboutUsingNestedContextConsumers = false;
75
- let hasWarnedAboutUsingConsumerUnstableRead = false;
56
let hasWarnedAboutUsingConsumerProvider = false;
57
58
if (__DEV__) {
@@ -83,17 +63,6 @@ export function createContext<T>(
63
$$typeof: REACT_CONTEXT_TYPE,
64
_context: context,
65
_calculateChangedBits: context._calculateChangedBits,
86
- unstable_read() {
87
- if (!hasWarnedAboutUsingConsumerUnstableRead) {
88
- hasWarnedAboutUsingConsumerUnstableRead = true;
89
- warning(
90
- false,
91
- 'Calling Context.Consumer.unstable_read() is not supported and will be removed in ' +
92
- 'a future major release. Did you mean to render Context.unstable_read() instead?',
93
- );
94
- }
95
- return context.unstable_read();
96
- },
66
};
67
// $FlowFixMe: Flow complains about not setting a value, which is intentional here
68
Object.defineProperties(Consumer, {
packages/react/src/__tests__/ReactContextValidator-test.js
+3
-3
@@ -556,7 +556,7 @@ describe('ReactContextValidator', () => {
556
}
557
558
expect(() => {
559
- expect(() => ReactTestUtils.renderIntoDocument(<ComponentA />)).toThrow();
559
+ ReactTestUtils.renderIntoDocument(<ComponentA />);
560
}).toWarnDev(
561
'Warning: ComponentA defines an invalid contextType. ' +
562
'contextType should point to the Context object returned by React.createContext(). ' +
@@ -565,10 +565,10 @@ describe('ReactContextValidator', () => {
565
);
566
567
// Warnings should be deduped by component type
568
- expect(() => ReactTestUtils.renderIntoDocument(<ComponentA />)).toThrow();
568
+ ReactTestUtils.renderIntoDocument(<ComponentA />);
569
570
expect(() => {
571
- expect(() => ReactTestUtils.renderIntoDocument(<ComponentB />)).toThrow();
571
+ ReactTestUtils.renderIntoDocument(<ComponentB />);
572
}).toWarnDev(
573
'Warning: ComponentB defines an invalid contextType. ' +
574
'contextType should point to the Context object returned by React.createContext(). ' +
packages/shared/ReactTypes.js
-1
@@ -54,7 +54,6 @@ export type ReactContext<T> = {
54
$$typeof: Symbol | number,
55
Consumer: ReactContext<T>,
56
Provider: ReactProviderType<T>,
57
- unstable_read: () => T,
57
58
_calculateChangedBits: ((a: T, b: T) => number) | null,
59