Add a feature flag to disable legacy context (#16269)
* Add a feature flag to disable legacy context * Address review - invariant -> warning - Make this.context and context argument actually undefined * Increase test coverage for lifecycles * Also disable it on the server is flag is on * Make this.context {} when disabled, but function context is undefined * Move checks inside
Dan Abramov committed
Aug 2, 2019 at 01:21 UTC
0c1ec049f8832d1c27f876844666fda393036800
14 files changed
+810
-278
packages/react-dom/src/__tests__/ReactDOMServerIntegrationLegacyContextDisabled-test.internal.js
new
+168
@@ -0,0 +1,168 @@
1
+/**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @emails react-core
8
+ */
9
+
10
+'use strict';
11
+
12
+const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegrationTestUtils');
13
+
14
+let React;
15
+let ReactDOM;
16
+let ReactFeatureFlags;
17
+let ReactDOMServer;
18
+let ReactTestUtils;
19
+
20
+function initModules() {
21
+ // Reset warning cache.
22
+ jest.resetModuleRegistry();
23
+ React = require('react');
24
+ ReactDOM = require('react-dom');
25
+ ReactDOMServer = require('react-dom/server');
26
+ ReactTestUtils = require('react-dom/test-utils');
27
+
28
+ ReactFeatureFlags = require('shared/ReactFeatureFlags');
29
+ ReactFeatureFlags.disableLegacyContext = true;
30
+
31
+ // Make them available to the helpers.
32
+ return {
33
+ ReactDOM,
34
+ ReactDOMServer,
35
+ ReactTestUtils,
36
+ };
37
+}
38
+
39
+const {resetModules, itRenders} = ReactDOMServerIntegrationUtils(initModules);
40
+
41
+function formatValue(val) {
42
+ if (val === null) {
43
+ return 'null';
44
+ }
45
+ if (val === undefined) {
46
+ return 'undefined';
47
+ }
48
+ if (typeof val === 'string') {
49
+ return val;
50
+ }
51
+ return JSON.stringify(val);
52
+}
53
+
54
+describe('ReactDOMServerIntegrationLegacyContextDisabled', () => {
55
+ beforeEach(() => {
56
+ resetModules();
57
+ });
58
+
59
+ itRenders('undefined legacy context with warning', async render => {
60
+ class LegacyProvider extends React.Component {
61
+ static childContextTypes = {
62
+ foo() {},
63
+ };
64
+ getChildContext() {
65
+ return {foo: 10};
66
+ }
67
+ render() {
68
+ return this.props.children;
69
+ }
70
+ }
71
+
72
+ let lifecycleContextLog = [];
73
+ class LegacyClsConsumer extends React.Component {
74
+ static contextTypes = {
75
+ foo() {},
76
+ };
77
+ shouldComponentUpdate(nextProps, nextState, nextContext) {
78
+ lifecycleContextLog.push(nextContext);
79
+ return true;
80
+ }
81
+ UNSAFE_componentWillReceiveProps(nextProps, nextContext) {
82
+ lifecycleContextLog.push(nextContext);
83
+ }
84
+ UNSAFE_componentWillUpdate(nextProps, nextState, nextContext) {
85
+ lifecycleContextLog.push(nextContext);
86
+ }
87
+ render() {
88
+ return formatValue(this.context);
89
+ }
90
+ }
91
+
92
+ function LegacyFnConsumer(props, context) {
93
+ return formatValue(context);
94
+ }
95
+ LegacyFnConsumer.contextTypes = {foo() {}};
96
+
97
+ function RegularFn(props, context) {
98
+ return formatValue(context);
99
+ }
100
+
101
+ const e = await render(
102
+ <LegacyProvider>
103
+ <span>
104
+ <LegacyClsConsumer />
105
+ <LegacyFnConsumer />
106
+ <RegularFn />
107
+ </span>
108
+ </LegacyProvider>,
109
+ 3,
110
+ );
111
+ expect(e.textContent).toBe('{}undefinedundefined');
112
+ expect(lifecycleContextLog).toEqual([]);
113
+ });
114
+
115
+ itRenders('modern context', async render => {
116
+ let Ctx = React.createContext();
117
+
118
+ class Provider extends React.Component {
119
+ render() {
120
+ return (
121
+ <Ctx.Provider value={this.props.value}>
122
+ {this.props.children}
123
+ </Ctx.Provider>
124
+ );
125
+ }
126
+ }
127
+
128
+ class RenderPropConsumer extends React.Component {
129
+ render() {
130
+ return <Ctx.Consumer>{value => formatValue(value)}</Ctx.Consumer>;
131
+ }
132
+ }
133
+
134
+ let lifecycleContextLog = [];
135
+ class ContextTypeConsumer extends React.Component {
136
+ static contextType = Ctx;
137
+ shouldComponentUpdate(nextProps, nextState, nextContext) {
138
+ lifecycleContextLog.push(nextContext);
139
+ return true;
140
+ }
141
+ UNSAFE_componentWillReceiveProps(nextProps, nextContext) {
142
+ lifecycleContextLog.push(nextContext);
143
+ }
144
+ UNSAFE_componentWillUpdate(nextProps, nextState, nextContext) {
145
+ lifecycleContextLog.push(nextContext);
146
+ }
147
+ render() {
148
+ return formatValue(this.context);
149
+ }
150
+ }
151
+
152
+ function FnConsumer() {
153
+ return formatValue(React.useContext(Ctx));
154
+ }
155
+
156
+ const e = await render(
157
+ <Provider value="a">
158
+ <span>
159
+ <RenderPropConsumer />
160
+ <ContextTypeConsumer />
161
+ <FnConsumer />
162
+ </span>
163
+ </Provider>,
164
+ );
165
+ expect(e.textContent).toBe('aaa');
166
+ expect(lifecycleContextLog).toEqual([]);
167
+ });
168
+});
packages/react-dom/src/__tests__/ReactLegacyContextDisabled-test.internal.js
new
+207
@@ -0,0 +1,207 @@
1
+/**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @emails react-core
8
+ */
9
+
10
+'use strict';
11
+
12
+let React;
13
+let ReactDOM;
14
+let ReactFeatureFlags;
15
+
16
+describe('ReactLegacyContextDisabled', () => {
17
+ beforeEach(() => {
18
+ jest.resetModules();
19
+
20
+ React = require('react');
21
+ ReactDOM = require('react-dom');
22
+ ReactFeatureFlags = require('shared/ReactFeatureFlags');
23
+ ReactFeatureFlags.disableLegacyContext = true;
24
+ });
25
+
26
+ function formatValue(val) {
27
+ if (val === null) {
28
+ return 'null';
29
+ }
30
+ if (val === undefined) {
31
+ return 'undefined';
32
+ }
33
+ if (typeof val === 'string') {
34
+ return val;
35
+ }
36
+ return JSON.stringify(val);
37
+ }
38
+
39
+ it('warns for legacy context', () => {
40
+ class LegacyProvider extends React.Component {
41
+ static childContextTypes = {
42
+ foo() {},
43
+ };
44
+ getChildContext() {
45
+ return {foo: 10};
46
+ }
47
+ render() {
48
+ return this.props.children;
49
+ }
50
+ }
51
+
52
+ let lifecycleContextLog = [];
53
+ class LegacyClsConsumer extends React.Component {
54
+ static contextTypes = {
55
+ foo() {},
56
+ };
57
+ shouldComponentUpdate(nextProps, nextState, nextContext) {
58
+ lifecycleContextLog.push(nextContext);
59
+ return true;
60
+ }
61
+ UNSAFE_componentWillReceiveProps(nextProps, nextContext) {
62
+ lifecycleContextLog.push(nextContext);
63
+ }
64
+ UNSAFE_componentWillUpdate(nextProps, nextState, nextContext) {
65
+ lifecycleContextLog.push(nextContext);
66
+ }
67
+ render() {
68
+ return formatValue(this.context);
69
+ }
70
+ }
71
+
72
+ function LegacyFnConsumer(props, context) {
73
+ return formatValue(context);
74
+ }
75
+ LegacyFnConsumer.contextTypes = {foo() {}};
76
+
77
+ function RegularFn(props, context) {
78
+ return formatValue(context);
79
+ }
80
+
81
+ const container = document.createElement('div');
82
+ expect(() => {
83
+ ReactDOM.render(
84
+ <LegacyProvider>
85
+ <span>
86
+ <LegacyClsConsumer />
87
+ <LegacyFnConsumer />
88
+ <RegularFn />
89
+ </span>
90
+ </LegacyProvider>,
91
+ container,
92
+ );
93
+ }).toWarnDev(
94
+ [
95
+ 'LegacyProvider uses the legacy childContextTypes API which is no longer supported. ' +
96
+ 'Use React.createContext() instead.',
97
+ 'LegacyClsConsumer uses the legacy contextTypes API which is no longer supported. ' +
98
+ 'Use React.createContext() with static contextType instead.',
99
+ 'LegacyFnConsumer uses the legacy contextTypes API which is no longer supported. ' +
100
+ 'Use React.createContext() with React.useContext() instead.',
101
+ ],
102
+ {withoutStack: true},
103
+ );
104
+ expect(container.textContent).toBe('{}undefinedundefined');
105
+ expect(lifecycleContextLog).toEqual([]);
106
+
107
+ // Test update path.
108
+ ReactDOM.render(
109
+ <LegacyProvider>
110
+ <span>
111
+ <LegacyClsConsumer />
112
+ <LegacyFnConsumer />
113
+ <RegularFn />
114
+ </span>
115
+ </LegacyProvider>,
116
+ container,
117
+ );
118
+ expect(container.textContent).toBe('{}undefinedundefined');
119
+ expect(lifecycleContextLog).toEqual([{}, {}, {}]);
120
+ ReactDOM.unmountComponentAtNode(container);
121
+ });
122
+
123
+ it('renders a tree with modern context', () => {
124
+ let Ctx = React.createContext();
125
+
126
+ class Provider extends React.Component {
127
+ render() {
128
+ return (
129
+ <Ctx.Provider value={this.props.value}>
130
+ {this.props.children}
131
+ </Ctx.Provider>
132
+ );
133
+ }
134
+ }
135
+
136
+ class RenderPropConsumer extends React.Component {
137
+ render() {
138
+ return <Ctx.Consumer>{value => formatValue(value)}</Ctx.Consumer>;
139
+ }
140
+ }
141
+
142
+ let lifecycleContextLog = [];
143
+ class ContextTypeConsumer extends React.Component {
144
+ static contextType = Ctx;
145
+ shouldComponentUpdate(nextProps, nextState, nextContext) {
146
+ lifecycleContextLog.push(nextContext);
147
+ return true;
148
+ }
149
+ UNSAFE_componentWillReceiveProps(nextProps, nextContext) {
150
+ lifecycleContextLog.push(nextContext);
151
+ }
152
+ UNSAFE_componentWillUpdate(nextProps, nextState, nextContext) {
153
+ lifecycleContextLog.push(nextContext);
154
+ }
155
+ render() {
156
+ return formatValue(this.context);
157
+ }
158
+ }
159
+
160
+ function FnConsumer() {
161
+ return formatValue(React.useContext(Ctx));
162
+ }
163
+
164
+ const container = document.createElement('div');
165
+ ReactDOM.render(
166
+ <Provider value="a">
167
+ <span>
168
+ <RenderPropConsumer />
169
+ <ContextTypeConsumer />
170
+ <FnConsumer />
171
+ </span>
172
+ </Provider>,
173
+ container,
174
+ );
175
+ expect(container.textContent).toBe('aaa');
176
+ expect(lifecycleContextLog).toEqual([]);
177
+
178
+ // Test update path
179
+ ReactDOM.render(
180
+ <Provider value="a">
181
+ <span>
182
+ <RenderPropConsumer />
183
+ <ContextTypeConsumer />
184
+ <FnConsumer />
185
+ </span>
186
+ </Provider>,
187
+ container,
188
+ );
189
+ expect(container.textContent).toBe('aaa');
190
+ expect(lifecycleContextLog).toEqual(['a', 'a', 'a']);
191
+ lifecycleContextLog.length = 0;
192
+
193
+ ReactDOM.render(
194
+ <Provider value="b">
195
+ <span>
196
+ <RenderPropConsumer />
197
+ <ContextTypeConsumer />
198
+ <FnConsumer />
199
+ </span>
200
+ </Provider>,
201
+ container,
202
+ );
203
+ expect(container.textContent).toBe('bbb');
204
+ expect(lifecycleContextLog).toEqual(['b', 'b']); // sCU skipped due to changed context value.
205
+ ReactDOM.unmountComponentAtNode(container);
206
+ });
207
+});
packages/react-dom/src/server/ReactPartialRenderer.js
+37
-21
@@ -21,6 +21,7 @@ import describeComponentFrame from 'shared/describeComponentFrame';
21
import ReactSharedInternals from 'shared/ReactSharedInternals';
22
import {
23
warnAboutDeprecatedLifecycles,
24
+ disableLegacyContext,
25
enableSuspenseServerRenderer,
26
enableFundamentalAPI,
27
enableFlareAPI,
@@ -430,7 +431,8 @@ function resolve(
431
432
// Extra closure so queue and replace can be captured properly
433
function processChild(element, Component) {
433
- let publicContext = processContext(Component, context, threadID);
434
+ const isClass = shouldConstruct(Component);
435
+ const publicContext = processContext(Component, context, threadID, isClass);
436
437
let queue = [];
438
let replace = false;
@@ -458,7 +460,7 @@ function resolve(
460
};
461
462
let inst;
461
- if (shouldConstruct(Component)) {
463
+ if (isClass) {
464
inst = new Component(element.props, publicContext, updater);
465
466
if (typeof Component.getDerivedStateFromProps === 'function') {
@@ -650,29 +652,43 @@ function resolve(
652
validateRenderResult(child, Component);
653
654
let childContext;
653
- if (typeof inst.getChildContext === 'function') {
654
- let childContextTypes = Component.childContextTypes;
655
- if (typeof childContextTypes === 'object') {
656
- childContext = inst.getChildContext();
657
- for (let contextKey in childContext) {
658
- invariant(
659
- contextKey in childContextTypes,
660
- '%s.getChildContext(): key "%s" is not defined in childContextTypes.',
655
+ if (disableLegacyContext) {
656
+ if (__DEV__) {
657
+ let childContextTypes = Component.childContextTypes;
658
+ if (childContextTypes !== undefined) {
659
+ warningWithoutStack(
660
+ false,
661
+ '%s uses the legacy childContextTypes API which is no longer supported. ' +
662
+ 'Use React.createContext() instead.',
663
getComponentName(Component) || 'Unknown',
662
- contextKey,
664
);
665
}
665
- } else {
666
- warningWithoutStack(
667
- false,
668
- '%s.getChildContext(): childContextTypes must be defined in order to ' +
669
- 'use getChildContext().',
670
- getComponentName(Component) || 'Unknown',
671
- );
666
}
673
- }
674
- if (childContext) {
675
- context = Object.assign({}, context, childContext);
667
+ } else {
668
+ if (typeof inst.getChildContext === 'function') {
669
+ let childContextTypes = Component.childContextTypes;
670
+ if (typeof childContextTypes === 'object') {
671
+ childContext = inst.getChildContext();
672
+ for (let contextKey in childContext) {
673
+ invariant(
674
+ contextKey in childContextTypes,
675
+ '%s.getChildContext(): key "%s" is not defined in childContextTypes.',
676
+ getComponentName(Component) || 'Unknown',
677
+ contextKey,
678
+ );
679
+ }
680
+ } else {
681
+ warningWithoutStack(
682
+ false,
683
+ '%s.getChildContext(): childContextTypes must be defined in order to ' +
684
+ 'use getChildContext().',
685
+ getComponentName(Component) || 'Unknown',
686
+ );
687
+ }
688
+ }
689
+ if (childContext) {
690
+ context = Object.assign({}, context, childContext);
691
+ }
692
}
693
}
694
return {child, context};
packages/react-dom/src/server/ReactPartialRendererContext.js
+87
-46
@@ -10,6 +10,7 @@
10
import type {ThreadID} from './ReactThreadIDAllocator';
11
import type {ReactContext} from 'shared/ReactTypes';
12
13
+import {disableLegacyContext} from 'shared/ReactFeatureFlags';
14
import {REACT_CONTEXT_TYPE, REACT_PROVIDER_TYPE} from 'shared/ReactSymbols';
15
import ReactSharedInternals from 'shared/ReactSharedInternals';
16
import getComponentName from 'shared/getComponentName';
@@ -73,60 +74,100 @@ export function processContext(
74
type: Function,
75
context: Object,
76
threadID: ThreadID,
77
+ isClass: boolean,
78
) {
77
- const contextType = type.contextType;
78
- if (__DEV__) {
79
- if ('contextType' in (type: any)) {
80
- let isValid =
81
- // Allow null for conditional declaration
82
- contextType === null ||
83
- (contextType !== undefined &&
84
- contextType.$$typeof === REACT_CONTEXT_TYPE &&
85
- contextType._context === undefined); // Not a <Context.Consumer>
79
+ if (isClass) {
80
+ const contextType = type.contextType;
81
+ if (__DEV__) {
82
+ if ('contextType' in (type: any)) {
83
+ let isValid =
84
+ // Allow null for conditional declaration
85
+ contextType === null ||
86
+ (contextType !== undefined &&
87
+ contextType.$$typeof === REACT_CONTEXT_TYPE &&
88
+ contextType._context === undefined); // Not a <Context.Consumer>
89
87
- if (!isValid && !didWarnAboutInvalidateContextType.has(type)) {
88
- didWarnAboutInvalidateContextType.add(type);
90
+ if (!isValid && !didWarnAboutInvalidateContextType.has(type)) {
91
+ didWarnAboutInvalidateContextType.add(type);
92
90
- let addendum = '';
91
- if (contextType === undefined) {
92
- addendum =
93
- ' However, it is set to undefined. ' +
94
- 'This can be caused by a typo or by mixing up named and default imports. ' +
95
- 'This can also happen due to a circular dependency, so ' +
96
- 'try moving the createContext() call to a separate file.';
97
- } else if (typeof contextType !== 'object') {
98
- addendum = ' However, it is set to a ' + typeof contextType + '.';
99
- } else if (contextType.$$typeof === REACT_PROVIDER_TYPE) {
100
- addendum = ' Did you accidentally pass the Context.Provider instead?';
101
- } else if (contextType._context !== undefined) {
102
- // <Context.Consumer>
103
- addendum = ' Did you accidentally pass the Context.Consumer instead?';
104
- } else {
105
- addendum =
106
- ' However, it is set to an object with keys {' +
107
- Object.keys(contextType).join(', ') +
108
- '}.';
93
+ let addendum = '';
94
+ if (contextType === undefined) {
95
+ addendum =
96
+ ' However, it is set to undefined. ' +
97
+ 'This can be caused by a typo or by mixing up named and default imports. ' +
98
+ 'This can also happen due to a circular dependency, so ' +
99
+ 'try moving the createContext() call to a separate file.';
100
+ } else if (typeof contextType !== 'object') {
101
+ addendum = ' However, it is set to a ' + typeof contextType + '.';
102
+ } else if (contextType.$$typeof === REACT_PROVIDER_TYPE) {
103
+ addendum =
104
+ ' Did you accidentally pass the Context.Provider instead?';
105
+ } else if (contextType._context !== undefined) {
106
+ // <Context.Consumer>
107
+ addendum =
108
+ ' Did you accidentally pass the Context.Consumer instead?';
109
+ } else {
110
+ addendum =
111
+ ' However, it is set to an object with keys {' +
112
+ Object.keys(contextType).join(', ') +
113
+ '}.';
114
+ }
115
+ warningWithoutStack(
116
+ false,
117
+ '%s defines an invalid contextType. ' +
118
+ 'contextType should point to the Context object returned by React.createContext().%s',
119
+ getComponentName(type) || 'Component',
120
+ addendum,
121
+ );
122
}
110
- warningWithoutStack(
111
- false,
112
- '%s defines an invalid contextType. ' +
113
- 'contextType should point to the Context object returned by React.createContext().%s',
114
- getComponentName(type) || 'Component',
115
- addendum,
116
- );
123
}
124
}
119
- }
120
- if (typeof contextType === 'object' && contextType !== null) {
121
- validateContextBounds(contextType, threadID);
122
- return contextType[threadID];
125
+ if (typeof contextType === 'object' && contextType !== null) {
126
+ validateContextBounds(contextType, threadID);
127
+ return contextType[threadID];
128
+ }
129
+ if (disableLegacyContext) {
130
+ if (__DEV__) {
131
+ if (type.contextTypes) {
132
+ warningWithoutStack(
133
+ false,
134
+ '%s uses the legacy contextTypes API which is no longer supported. ' +
135
+ 'Use React.createContext() with static contextType instead.',
136
+ getComponentName(type) || 'Unknown',
137
+ );
138
+ }
139
+ }
140
+ return emptyObject;
141
+ } else {
142
+ const maskedContext = maskContext(type, context);
143
+ if (__DEV__) {
144
+ if (type.contextTypes) {
145
+ checkContextTypes(type.contextTypes, maskedContext, 'context');
146
+ }
147
+ }
148
+ return maskedContext;
149
+ }
150
} else {
124
- const maskedContext = maskContext(type, context);
125
- if (__DEV__) {
126
- if (type.contextTypes) {
127
- checkContextTypes(type.contextTypes, maskedContext, 'context');
151
+ if (disableLegacyContext) {
152
+ if (__DEV__) {
153
+ if (type.contextTypes) {
154
+ warningWithoutStack(
155
+ false,
156
+ '%s uses the legacy contextTypes API which is no longer supported. ' +
157
+ 'Use React.createContext() with React.useContext() instead.',
158
+ getComponentName(type) || 'Unknown',
159
+ );
160
+ }
161
+ }
162
+ return undefined;
163
+ } else {
164
+ const maskedContext = maskContext(type, context);
165
+ if (__DEV__) {
166
+ if (type.contextTypes) {
167
+ checkContextTypes(type.contextTypes, maskedContext, 'context');
168
+ }
169
}
170
+ return maskedContext;
171
}
130
- return maskedContext;
172
}
173
}
packages/react-reconciler/src/ReactFiberBeginWork.js
+24
-4
@@ -57,6 +57,7 @@ import ReactSharedInternals from 'shared/ReactSharedInternals';
57
import {
58
debugRenderPhaseSideEffects,
59
debugRenderPhaseSideEffectsForStrictMode,
60
+ disableLegacyContext,
61
enableProfilerTimer,
62
enableSchedulerTracing,
63
enableSuspenseServerRenderer,
@@ -615,8 +616,11 @@ function updateFunctionComponent(
616
}
617
}
618
618
- const unmaskedContext = getUnmaskedContext(workInProgress, Component, true);
619
- const context = getMaskedContext(workInProgress, unmaskedContext);
619
+ let context;
620
+ if (!disableLegacyContext) {
621
+ const unmaskedContext = getUnmaskedContext(workInProgress, Component, true);
622
+ context = getMaskedContext(workInProgress, unmaskedContext);
623
+ }
624
625
let nextChildren;
626
prepareToReadContext(workInProgress, renderExpirationTime);
@@ -1230,8 +1234,15 @@ function mountIndeterminateComponent(
1234
}
1235
1236
const props = workInProgress.pendingProps;
1233
- const unmaskedContext = getUnmaskedContext(workInProgress, Component, false);
1234
- const context = getMaskedContext(workInProgress, unmaskedContext);
1237
+ let context;
1238
+ if (!disableLegacyContext) {
1239
+ const unmaskedContext = getUnmaskedContext(
1240
+ workInProgress,
1241
+ Component,
1242
+ false,
1243
+ );
1244
+ context = getMaskedContext(workInProgress, unmaskedContext);
1245
+ }
1246
1247
prepareToReadContext(workInProgress, renderExpirationTime);
1248
let value;
@@ -1349,6 +1360,15 @@ function mountIndeterminateComponent(
1360
// Proceed under the assumption that this is a function component
1361
workInProgress.tag = FunctionComponent;
1362
if (__DEV__) {
1363
+ if (disableLegacyContext && Component.contextTypes) {
1364
+ warningWithoutStack(
1365
+ false,
1366
+ '%s uses the legacy contextTypes API which is no longer supported. ' +
1367
+ 'Use React.createContext() with React.useContext() instead.',
1368
+ getComponentName(Component) || 'Unknown',
1369
+ );
1370
+ }
1371
+
1372
if (
1373
debugRenderPhaseSideEffects ||
1374
(debugRenderPhaseSideEffectsForStrictMode &&
packages/react-reconciler/src/ReactFiberClassComponent.js
+45
-22
@@ -15,6 +15,7 @@ import {Update, Snapshot} from 'shared/ReactSideEffectTags';
15
import {
16
debugRenderPhaseSideEffects,
17
debugRenderPhaseSideEffectsForStrictMode,
18
+ disableLegacyContext,
19
warnAboutDeprecatedLifecycles,
20
} from 'shared/ReactFeatureFlags';
21
import ReactStrictModeWarnings from './ReactStrictModeWarnings';
@@ -361,26 +362,46 @@ function checkClassInstance(workInProgress: Fiber, ctor: any, newProps: any) {
362
'property to define contextType instead.',
363
name,
364
);
364
- const noInstanceContextTypes = !instance.contextTypes;
365
- warningWithoutStack(
366
- noInstanceContextTypes,
367
- 'contextTypes was defined as an instance property on %s. Use a static ' +
368
- 'property to define contextTypes instead.',
369
- name,
370
- );
365
372
- if (
373
- ctor.contextType &&
374
- ctor.contextTypes &&
375
- !didWarnAboutContextTypeAndContextTypes.has(ctor)
376
- ) {
377
- didWarnAboutContextTypeAndContextTypes.add(ctor);
366
+ if (disableLegacyContext) {
367
+ if (ctor.childContextTypes) {
368
+ warningWithoutStack(
369
+ false,
370
+ '%s uses the legacy childContextTypes API which is no longer supported. ' +
371
+ 'Use React.createContext() instead.',
372
+ name,
373
+ );
374
+ }
375
+ if (ctor.contextTypes) {
376
+ warningWithoutStack(
377
+ false,
378
+ '%s uses the legacy contextTypes API which is no longer supported. ' +
379
+ 'Use React.createContext() with static contextType instead.',
380
+ name,
381
+ );
382
+ }
383
+ } else {
384
+ const noInstanceContextTypes = !instance.contextTypes;
385
warningWithoutStack(
379
- false,
380
- '%s declares both contextTypes and contextType static properties. ' +
381
- 'The legacy contextTypes property will be ignored.',
386
+ noInstanceContextTypes,
387
+ 'contextTypes was defined as an instance property on %s. Use a static ' +
388
+ 'property to define contextTypes instead.',
389
name,
390
);
391
+
392
+ if (
393
+ ctor.contextType &&
394
+ ctor.contextTypes &&
395
+ !didWarnAboutContextTypeAndContextTypes.has(ctor)
396
+ ) {
397
+ didWarnAboutContextTypeAndContextTypes.add(ctor);
398
+ warningWithoutStack(
399
+ false,
400
+ '%s declares both contextTypes and contextType static properties. ' +
401
+ 'The legacy contextTypes property will be ignored.',
402
+ name,
403
+ );
404
+ }
405
}
406
407
const noComponentShouldUpdate =
@@ -534,7 +555,7 @@ function constructClassInstance(
555
): any {
556
let isLegacyContextConsumer = false;
557
let unmaskedContext = emptyContextObject;
537
- let context = null;
558
+ let context = emptyContextObject;
559
const contextType = ctor.contextType;
560
561
if (__DEV__) {
@@ -582,7 +603,7 @@ function constructClassInstance(
603
604
if (typeof contextType === 'object' && contextType !== null) {
605
context = readContext((contextType: any));
585
- } else {
606
+ } else if (!disableLegacyContext) {
607
unmaskedContext = getUnmaskedContext(workInProgress, ctor, true);
608
const contextTypes = ctor.contextTypes;
609
isLegacyContextConsumer =
@@ -785,6 +806,8 @@ function mountClassInstance(
806
const contextType = ctor.contextType;
807
if (typeof contextType === 'object' && contextType !== null) {
808
instance.context = readContext(contextType);
809
+ } else if (disableLegacyContext) {
810
+ instance.context = emptyContextObject;
811
} else {
812
const unmaskedContext = getUnmaskedContext(workInProgress, ctor, true);
813
instance.context = getMaskedContext(workInProgress, unmaskedContext);
@@ -885,10 +908,10 @@ function resumeMountClassInstance(
908
909
const oldContext = instance.context;
910
const contextType = ctor.contextType;
888
- let nextContext;
911
+ let nextContext = emptyContextObject;
912
if (typeof contextType === 'object' && contextType !== null) {
913
nextContext = readContext(contextType);
891
- } else {
914
+ } else if (!disableLegacyContext) {
915
const nextLegacyUnmaskedContext = getUnmaskedContext(
916
workInProgress,
917
ctor,
@@ -1034,10 +1057,10 @@ function updateClassInstance(
1057
1058
const oldContext = instance.context;
1059
const contextType = ctor.contextType;
1037
- let nextContext;
1060
+ let nextContext = emptyContextObject;
1061
if (typeof contextType === 'object' && contextType !== null) {
1062
nextContext = readContext(contextType);
1040
- } else {
1063
+ } else if (!disableLegacyContext) {
1064
const nextUnmaskedContext = getUnmaskedContext(workInProgress, ctor, true);
1065
nextContext = getMaskedContext(workInProgress, nextUnmaskedContext);
1066
}
packages/react-reconciler/src/ReactFiberContext.js
+234
-185
@@ -11,6 +11,7 @@ import type {Fiber} from './ReactFiber';
11
import type {StackCursor} from './ReactFiberStack';
12
13
import {isFiberMounted} from 'react-reconciler/reflection';
14
+import {disableLegacyContext} from 'shared/ReactFeatureFlags';
15
import {ClassComponent, HostRoot} from 'shared/ReactWorkTags';
16
import getComponentName from 'shared/getComponentName';
17
import invariant from 'shared/invariant';
@@ -46,14 +47,18 @@ function getUnmaskedContext(
47
Component: Function,
48
didPushOwnContextIfProvider: boolean,
49
): Object {
49
- if (didPushOwnContextIfProvider && isContextProvider(Component)) {
50
- // If the fiber is a context provider itself, when we read its context
51
- // we may have already pushed its own child context on the stack. A context
52
- // provider should not "see" its own child context. Therefore we read the
53
- // previous (parent) context instead for a context provider.
54
- return previousContext;
50
+ if (disableLegacyContext) {
51
+ return emptyContextObject;
52
+ } else {
53
+ if (didPushOwnContextIfProvider && isContextProvider(Component)) {
54
+ // If the fiber is a context provider itself, when we read its context
55
+ // we may have already pushed its own child context on the stack. A context
56
+ // provider should not "see" its own child context. Therefore we read the
57
+ // previous (parent) context instead for a context provider.
58
+ return previousContext;
59
+ }
60
+ return contextStackCursor.current;
61
}
56
- return contextStackCursor.current;
62
}
63
64
function cacheContext(
@@ -61,74 +66,98 @@ function cacheContext(
66
unmaskedContext: Object,
67
maskedContext: Object,
68
): void {
64
- const instance = workInProgress.stateNode;
65
- instance.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext;
66
- instance.__reactInternalMemoizedMaskedChildContext = maskedContext;
69
+ if (disableLegacyContext) {
70
+ return;
71
+ } else {
72
+ const instance = workInProgress.stateNode;
73
+ instance.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext;
74
+ instance.__reactInternalMemoizedMaskedChildContext = maskedContext;
75
+ }
76
}
77
78
function getMaskedContext(
79
workInProgress: Fiber,
80
unmaskedContext: Object,
81
): Object {
73
- const type = workInProgress.type;
74
- const contextTypes = type.contextTypes;
75
- if (!contextTypes) {
82
+ if (disableLegacyContext) {
83
return emptyContextObject;
77
- }
84
+ } else {
85
+ const type = workInProgress.type;
86
+ const contextTypes = type.contextTypes;
87
+ if (!contextTypes) {
88
+ return emptyContextObject;
89
+ }
90
79
- // Avoid recreating masked context unless unmasked context has changed.
80
- // Failing to do this will result in unnecessary calls to componentWillReceiveProps.
81
- // This may trigger infinite loops if componentWillReceiveProps calls setState.
82
- const instance = workInProgress.stateNode;
83
- if (
84
- instance &&
85
- instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext
86
- ) {
87
- return instance.__reactInternalMemoizedMaskedChildContext;
88
- }
91
+ // Avoid recreating masked context unless unmasked context has changed.
92
+ // Failing to do this will result in unnecessary calls to componentWillReceiveProps.
93
+ // This may trigger infinite loops if componentWillReceiveProps calls setState.
94
+ const instance = workInProgress.stateNode;
95
+ if (
96
+ instance &&
97
+ instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext
98
+ ) {
99
+ return instance.__reactInternalMemoizedMaskedChildContext;
100
+ }
101
90
- const context = {};
91
- for (let key in contextTypes) {
92
- context[key] = unmaskedContext[key];
93
- }
102
+ const context = {};
103
+ for (let key in contextTypes) {
104
+ context[key] = unmaskedContext[key];
105
+ }
106
95
- if (__DEV__) {
96
- const name = getComponentName(type) || 'Unknown';
97
- checkPropTypes(
98
- contextTypes,
99
- context,
100
- 'context',
101
- name,
102
- getCurrentFiberStackInDev,
103
- );
104
- }
107
+ if (__DEV__) {
108
+ const name = getComponentName(type) || 'Unknown';
109
+ checkPropTypes(
110
+ contextTypes,
111
+ context,
112
+ 'context',
113
+ name,
114
+ getCurrentFiberStackInDev,
115
+ );
116
+ }
117
106
- // Cache unmasked context so we can avoid recreating masked context unless necessary.
107
- // Context is created before the class component is instantiated so check for instance.
108
- if (instance) {
109
- cacheContext(workInProgress, unmaskedContext, context);
110
- }
118
+ // Cache unmasked context so we can avoid recreating masked context unless necessary.
119
+ // Context is created before the class component is instantiated so check for instance.
120
+ if (instance) {
121
+ cacheContext(workInProgress, unmaskedContext, context);
122
+ }
123
112
- return context;
124
+ return context;
125
+ }
126
}
127
128
function hasContextChanged(): boolean {
116
- return didPerformWorkStackCursor.current;
129
+ if (disableLegacyContext) {
130
+ return false;
131
+ } else {
132
+ return didPerformWorkStackCursor.current;
133
+ }
134
}
135
136
function isContextProvider(type: Function): boolean {
120
- const childContextTypes = type.childContextTypes;
121
- return childContextTypes !== null && childContextTypes !== undefined;
137
+ if (disableLegacyContext) {
138
+ return false;
139
+ } else {
140
+ const childContextTypes = type.childContextTypes;
141
+ return childContextTypes !== null && childContextTypes !== undefined;
142
+ }
143
}
144
145
function popContext(fiber: Fiber): void {
125
- pop(didPerformWorkStackCursor, fiber);
126
- pop(contextStackCursor, fiber);
146
+ if (disableLegacyContext) {
147
+ return;
148
+ } else {
149
+ pop(didPerformWorkStackCursor, fiber);
150
+ pop(contextStackCursor, fiber);
151
+ }
152
}
153
154
function popTopLevelContextObject(fiber: Fiber): void {
130
- pop(didPerformWorkStackCursor, fiber);
131
- pop(contextStackCursor, fiber);
155
+ if (disableLegacyContext) {
156
+ return;
157
+ } else {
158
+ pop(didPerformWorkStackCursor, fiber);
159
+ pop(contextStackCursor, fiber);
160
+ }
161
}
162
163
function pushTopLevelContextObject(
@@ -136,14 +165,18 @@ function pushTopLevelContextObject(
165
context: Object,
166
didChange: boolean,
167
): void {
139
- invariant(
140
- contextStackCursor.current === emptyContextObject,
141
- 'Unexpected context found on stack. ' +
142
- 'This error is likely caused by a bug in React. Please file an issue.',
143
- );
144
-
145
- push(contextStackCursor, context, fiber);
146
- push(didPerformWorkStackCursor, didChange, fiber);
168
+ if (disableLegacyContext) {
169
+ return;
170
+ } else {
171
+ invariant(
172
+ contextStackCursor.current === emptyContextObject,
173
+ 'Unexpected context found on stack. ' +
174
+ 'This error is likely caused by a bug in React. Please file an issue.',
175
+ );
176
+
177
+ push(contextStackCursor, context, fiber);
178
+ push(didPerformWorkStackCursor, didChange, fiber);
179
+ }
180
}
181
182
function processChildContext(
@@ -151,87 +184,95 @@ function processChildContext(
184
type: any,
185
parentContext: Object,
186
): Object {
154
- const instance = fiber.stateNode;
155
- const childContextTypes = type.childContextTypes;
187
+ if (disableLegacyContext) {
188
+ return parentContext;
189
+ } else {
190
+ const instance = fiber.stateNode;
191
+ const childContextTypes = type.childContextTypes;
192
+
193
+ // TODO (bvaughn) Replace this behavior with an invariant() in the future.
194
+ // It has only been added in Fiber to match the (unintentional) behavior in Stack.
195
+ if (typeof instance.getChildContext !== 'function') {
196
+ if (__DEV__) {
197
+ const componentName = getComponentName(type) || 'Unknown';
198
+
199
+ if (!warnedAboutMissingGetChildContext[componentName]) {
200
+ warnedAboutMissingGetChildContext[componentName] = true;
201
+ warningWithoutStack(
202
+ false,
203
+ '%s.childContextTypes is specified but there is no getChildContext() method ' +
204
+ 'on the instance. You can either define getChildContext() on %s or remove ' +
205
+ 'childContextTypes from it.',
206
+ componentName,
207
+ componentName,
208
+ );
209
+ }
210
+ }
211
+ return parentContext;
212
+ }
213
157
- // TODO (bvaughn) Replace this behavior with an invariant() in the future.
158
- // It has only been added in Fiber to match the (unintentional) behavior in Stack.
159
- if (typeof instance.getChildContext !== 'function') {
214
+ let childContext;
215
if (__DEV__) {
161
- const componentName = getComponentName(type) || 'Unknown';
162
-
163
- if (!warnedAboutMissingGetChildContext[componentName]) {
164
- warnedAboutMissingGetChildContext[componentName] = true;
165
- warningWithoutStack(
166
- false,
167
- '%s.childContextTypes is specified but there is no getChildContext() method ' +
168
- 'on the instance. You can either define getChildContext() on %s or remove ' +
169
- 'childContextTypes from it.',
170
- componentName,
171
- componentName,
172
- );
173
- }
216
+ setCurrentPhase('getChildContext');
217
+ }
218
+ startPhaseTimer(fiber, 'getChildContext');
219
+ childContext = instance.getChildContext();
220
+ stopPhaseTimer();
221
+ if (__DEV__) {
222
+ setCurrentPhase(null);
223
+ }
224
+ for (let contextKey in childContext) {
225
+ invariant(
226
+ contextKey in childContextTypes,
227
+ '%s.getChildContext(): key "%s" is not defined in childContextTypes.',
228
+ getComponentName(type) || 'Unknown',
229
+ contextKey,
230
+ );
231
+ }
232
+ if (__DEV__) {
233
+ const name = getComponentName(type) || 'Unknown';
234
+ checkPropTypes(
235
+ childContextTypes,
236
+ childContext,
237
+ 'child context',
238
+ name,
239
+ // In practice, there is one case in which we won't get a stack. It's when
240
+ // somebody calls unstable_renderSubtreeIntoContainer() and we process
241
+ // context from the parent component instance. The stack will be missing
242
+ // because it's outside of the reconciliation, and so the pointer has not
243
+ // been set. This is rare and doesn't matter. We'll also remove that API.
244
+ getCurrentFiberStackInDev,
245
+ );
246
}
175
- return parentContext;
176
- }
247
178
- let childContext;
179
- if (__DEV__) {
180
- setCurrentPhase('getChildContext');
248
+ return {...parentContext, ...childContext};
249
}
182
- startPhaseTimer(fiber, 'getChildContext');
183
- childContext = instance.getChildContext();
184
- stopPhaseTimer();
185
- if (__DEV__) {
186
- setCurrentPhase(null);
187
- }
188
- for (let contextKey in childContext) {
189
- invariant(
190
- contextKey in childContextTypes,
191
- '%s.getChildContext(): key "%s" is not defined in childContextTypes.',
192
- getComponentName(type) || 'Unknown',
193
- contextKey,
194
- );
195
- }
196
- if (__DEV__) {
197
- const name = getComponentName(type) || 'Unknown';
198
- checkPropTypes(
199
- childContextTypes,
200
- childContext,
201
- 'child context',
202
- name,
203
- // In practice, there is one case in which we won't get a stack. It's when
204
- // somebody calls unstable_renderSubtreeIntoContainer() and we process
205
- // context from the parent component instance. The stack will be missing
206
- // because it's outside of the reconciliation, and so the pointer has not
207
- // been set. This is rare and doesn't matter. We'll also remove that API.
208
- getCurrentFiberStackInDev,
209
- );
210
- }
211
-
212
- return {...parentContext, ...childContext};
250
}
251
252
function pushContextProvider(workInProgress: Fiber): boolean {
216
- const instance = workInProgress.stateNode;
217
- // We push the context as early as possible to ensure stack integrity.
218
- // If the instance does not exist yet, we will push null at first,
219
- // and replace it on the stack later when invalidating the context.
220
- const memoizedMergedChildContext =
221
- (instance && instance.__reactInternalMemoizedMergedChildContext) ||
222
- emptyContextObject;
223
-
224
- // Remember the parent context so we can merge with it later.
225
- // Inherit the parent's did-perform-work value to avoid inadvertently blocking updates.
226
- previousContext = contextStackCursor.current;
227
- push(contextStackCursor, memoizedMergedChildContext, workInProgress);
228
- push(
229
- didPerformWorkStackCursor,
230
- didPerformWorkStackCursor.current,
231
- workInProgress,
232
- );
233
-
234
- return true;
253
+ if (disableLegacyContext) {
254
+ return false;
255
+ } else {
256
+ const instance = workInProgress.stateNode;
257
+ // We push the context as early as possible to ensure stack integrity.
258
+ // If the instance does not exist yet, we will push null at first,
259
+ // and replace it on the stack later when invalidating the context.
260
+ const memoizedMergedChildContext =
261
+ (instance && instance.__reactInternalMemoizedMergedChildContext) ||
262
+ emptyContextObject;
263
+
264
+ // Remember the parent context so we can merge with it later.
265
+ // Inherit the parent's did-perform-work value to avoid inadvertently blocking updates.
266
+ previousContext = contextStackCursor.current;
267
+ push(contextStackCursor, memoizedMergedChildContext, workInProgress);
268
+ push(
269
+ didPerformWorkStackCursor,
270
+ didPerformWorkStackCursor.current,
271
+ workInProgress,
272
+ );
273
+
274
+ return true;
275
+ }
276
}
277
278
function invalidateContextProvider(
@@ -239,66 +280,74 @@ function invalidateContextProvider(
280
type: any,
281
didChange: boolean,
282
): void {
242
- const instance = workInProgress.stateNode;
243
- invariant(
244
- instance,
245
- 'Expected to have an instance by this point. ' +
246
- 'This error is likely caused by a bug in React. Please file an issue.',
247
- );
248
-
249
- if (didChange) {
250
- // Merge parent and own context.
251
- // Skip this if we're not updating due to sCU.
252
- // This avoids unnecessarily recomputing memoized values.
253
- const mergedContext = processChildContext(
254
- workInProgress,
255
- type,
256
- previousContext,
257
- );
258
- instance.__reactInternalMemoizedMergedChildContext = mergedContext;
259
-
260
- // Replace the old (or empty) context with the new one.
261
- // It is important to unwind the context in the reverse order.
262
- pop(didPerformWorkStackCursor, workInProgress);
263
- pop(contextStackCursor, workInProgress);
264
- // Now push the new context and mark that it has changed.
265
- push(contextStackCursor, mergedContext, workInProgress);
266
- push(didPerformWorkStackCursor, didChange, workInProgress);
283
+ if (disableLegacyContext) {
284
+ return;
285
} else {
268
- pop(didPerformWorkStackCursor, workInProgress);
269
- push(didPerformWorkStackCursor, didChange, workInProgress);
286
+ const instance = workInProgress.stateNode;
287
+ invariant(
288
+ instance,
289
+ 'Expected to have an instance by this point. ' +
290
+ 'This error is likely caused by a bug in React. Please file an issue.',
291
+ );
292
+
293
+ if (didChange) {
294
+ // Merge parent and own context.
295
+ // Skip this if we're not updating due to sCU.
296
+ // This avoids unnecessarily recomputing memoized values.
297
+ const mergedContext = processChildContext(
298
+ workInProgress,
299
+ type,
300
+ previousContext,
301
+ );
302
+ instance.__reactInternalMemoizedMergedChildContext = mergedContext;
303
+
304
+ // Replace the old (or empty) context with the new one.
305
+ // It is important to unwind the context in the reverse order.
306
+ pop(didPerformWorkStackCursor, workInProgress);
307
+ pop(contextStackCursor, workInProgress);
308
+ // Now push the new context and mark that it has changed.
309
+ push(contextStackCursor, mergedContext, workInProgress);
310
+ push(didPerformWorkStackCursor, didChange, workInProgress);
311
+ } else {
312
+ pop(didPerformWorkStackCursor, workInProgress);
313
+ push(didPerformWorkStackCursor, didChange, workInProgress);
314
+ }
315
}
316
}
317
318
function findCurrentUnmaskedContext(fiber: Fiber): Object {
274
- // Currently this is only used with renderSubtreeIntoContainer; not sure if it
275
- // makes sense elsewhere
276
- invariant(
277
- isFiberMounted(fiber) && fiber.tag === ClassComponent,
278
- 'Expected subtree parent to be a mounted class component. ' +
279
- 'This error is likely caused by a bug in React. Please file an issue.',
280
- );
281
-
282
- let node = fiber;
283
- do {
284
- switch (node.tag) {
285
- case HostRoot:
286
- return node.stateNode.context;
287
- case ClassComponent: {
288
- const Component = node.type;
289
- if (isContextProvider(Component)) {
290
- return node.stateNode.__reactInternalMemoizedMergedChildContext;
319
+ if (disableLegacyContext) {
320
+ return emptyContextObject;
321
+ } else {
322
+ // Currently this is only used with renderSubtreeIntoContainer; not sure if it
323
+ // makes sense elsewhere
324
+ invariant(
325
+ isFiberMounted(fiber) && fiber.tag === ClassComponent,
326
+ 'Expected subtree parent to be a mounted class component. ' +
327
+ 'This error is likely caused by a bug in React. Please file an issue.',
328
+ );
329
+
330
+ let node = fiber;
331
+ do {
332
+ switch (node.tag) {
333
+ case HostRoot:
334
+ return node.stateNode.context;
335
+ case ClassComponent: {
336
+ const Component = node.type;
337
+ if (isContextProvider(Component)) {
338
+ return node.stateNode.__reactInternalMemoizedMergedChildContext;
339
+ }
340
+ break;
341
}
292
- break;
342
}
294
- }
295
- node = node.return;
296
- } while (node !== null);
297
- invariant(
298
- false,
299
- 'Found unexpected detached subtree parent. ' +
300
- 'This error is likely caused by a bug in React. Please file an issue.',
301
- );
343
+ node = node.return;
344
+ } while (node !== null);
345
+ invariant(
346
+ false,
347
+ 'Found unexpected detached subtree parent. ' +
348
+ 'This error is likely caused by a bug in React. Please file an issue.',
349
+ );
350
+ }
351
}
352
353
export {
packages/shared/ReactFeatureFlags.js
+2
@@ -92,3 +92,5 @@ export const enableSuspenseCallback = false;
92
// from React.createElement to React.jsx
93
// https://github.com/reactjs/rfcs/blob/createlement-rfc/text/0000-create-element-changes.md
94
export const warnAboutDefaultPropsOnFunctionComponents = false;
95
+
96
+export const disableLegacyContext = false;
packages/shared/forks/ReactFeatureFlags.native-fb.js
+1
@@ -40,6 +40,7 @@ export const flushSuspenseFallbacksInTests = true;
40
export const enableUserBlockingEvents = false;
41
export const enableSuspenseCallback = false;
42
export const warnAboutDefaultPropsOnFunctionComponents = false;
43
+export const disableLegacyContext = false;
44
45
// Only used in www builds.
46
export function addUserTimingListener() {
packages/shared/forks/ReactFeatureFlags.native-oss.js
+1
@@ -35,6 +35,7 @@ export const flushSuspenseFallbacksInTests = true;
35
export const enableUserBlockingEvents = false;
36
export const enableSuspenseCallback = false;
37
export const warnAboutDefaultPropsOnFunctionComponents = false;
38
+export const disableLegacyContext = false;
39
40
// Only used in www builds.
41
export function addUserTimingListener() {
packages/shared/forks/ReactFeatureFlags.persistent.js
+1
@@ -35,6 +35,7 @@ export const flushSuspenseFallbacksInTests = true;
35
export const enableUserBlockingEvents = false;
36
export const enableSuspenseCallback = false;
37
export const warnAboutDefaultPropsOnFunctionComponents = false;
38
+export const disableLegacyContext = false;
39
40
// Only used in www builds.
41
export function addUserTimingListener() {
packages/shared/forks/ReactFeatureFlags.test-renderer.js
+1
@@ -35,6 +35,7 @@ export const flushSuspenseFallbacksInTests = true;
35
export const enableUserBlockingEvents = false;
36
export const enableSuspenseCallback = false;
37
export const warnAboutDefaultPropsOnFunctionComponents = false;
38
+export const disableLegacyContext = false;
39
40
// Only used in www builds.
41
export function addUserTimingListener() {
packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
+1
@@ -35,6 +35,7 @@ export const flushSuspenseFallbacksInTests = true;
35
export const enableUserBlockingEvents = false;
36
export const enableSuspenseCallback = true;
37
export const warnAboutDefaultPropsOnFunctionComponents = false;
38
+export const disableLegacyContext = false;
39
40
// Only used in www builds.
41
export function addUserTimingListener() {
packages/shared/forks/ReactFeatureFlags.www.js
+1
@@ -21,6 +21,7 @@ export const {
21
warnAboutDeprecatedSetNativeProps,
22
revertPassiveEffectsChange,
23
enableUserBlockingEvents,
24
+ disableLegacyContext,
25
} = require('ReactFeatureFlags');
26
27
// In www, we have experimental support for gathering data