@samitouri / QOS-React / commits / 7685b55d27

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