Add unstable_renderSubtreeIntoContainer and unstable_createPortal feature flags (#17880)
Dominic Gannaway committed
Jan 21, 2020 at 21:17 UTC
c322f5913f5ec4f0f8d7926ba7401e94c0aaa772
11 files changed
+377
-316
packages/react-dom/src/__tests__/ReactDOMFiber-test.js
+26
-22
@@ -13,6 +13,8 @@ const React = require('react');
13
const ReactDOM = require('react-dom');
14
const PropTypes = require('prop-types');
15
16
+const ReactFeatureFlags = require('shared/ReactFeatureFlags');
17
+
18
describe('ReactDOMFiber', () => {
19
let container;
20
@@ -247,30 +249,32 @@ describe('ReactDOMFiber', () => {
249
});
250
251
// TODO: remove in React 17
250
- it('should support unstable_createPortal alias', () => {
251
- const portalContainer = document.createElement('div');
252
+ if (!ReactFeatureFlags.disableUnstableCreatePortal) {
253
+ it('should support unstable_createPortal alias', () => {
254
+ const portalContainer = document.createElement('div');
255
253
- expect(() =>
254
- ReactDOM.render(
255
- <div>
256
- {ReactDOM.unstable_createPortal(<div>portal</div>, portalContainer)}
257
- </div>,
258
- container,
259
- ),
260
- ).toWarnDev(
261
- 'The ReactDOM.unstable_createPortal() alias has been deprecated, ' +
262
- 'and will be removed in React 17+. Update your code to use ' +
263
- 'ReactDOM.createPortal() instead. It has the exact same API, ' +
264
- 'but without the "unstable_" prefix.',
265
- {withoutStack: true},
266
- );
267
- expect(portalContainer.innerHTML).toBe('<div>portal</div>');
268
- expect(container.innerHTML).toBe('<div></div>');
256
+ expect(() =>
257
+ ReactDOM.render(
258
+ <div>
259
+ {ReactDOM.unstable_createPortal(<div>portal</div>, portalContainer)}
260
+ </div>,
261
+ container,
262
+ ),
263
+ ).toWarnDev(
264
+ 'The ReactDOM.unstable_createPortal() alias has been deprecated, ' +
265
+ 'and will be removed in React 17+. Update your code to use ' +
266
+ 'ReactDOM.createPortal() instead. It has the exact same API, ' +
267
+ 'but without the "unstable_" prefix.',
268
+ {withoutStack: true},
269
+ );
270
+ expect(portalContainer.innerHTML).toBe('<div>portal</div>');
271
+ expect(container.innerHTML).toBe('<div></div>');
272
270
- ReactDOM.unmountComponentAtNode(container);
271
- expect(portalContainer.innerHTML).toBe('');
272
- expect(container.innerHTML).toBe('');
273
- });
273
+ ReactDOM.unmountComponentAtNode(container);
274
+ expect(portalContainer.innerHTML).toBe('');
275
+ expect(container.innerHTML).toBe('');
276
+ });
277
+ }
278
279
it('should render many portals', () => {
280
const portalContainer1 = document.createElement('div');
packages/react-dom/src/__tests__/renderSubtreeIntoContainer-test.js
+289
-275
@@ -16,308 +16,322 @@ const ReactTestUtils = require('react-dom/test-utils');
16
const renderSubtreeIntoContainer = require('react-dom')
17
.unstable_renderSubtreeIntoContainer;
18
19
-describe('renderSubtreeIntoContainer', () => {
20
- it('should pass context when rendering subtree elsewhere', () => {
21
- const portal = document.createElement('div');
22
-
23
- class Component extends React.Component {
24
- static contextTypes = {
25
- foo: PropTypes.string.isRequired,
26
- };
27
-
28
- render() {
29
- return <div>{this.context.foo}</div>;
30
- }
31
- }
32
-
33
- class Parent extends React.Component {
34
- static childContextTypes = {
35
- foo: PropTypes.string.isRequired,
36
- };
37
-
38
- getChildContext() {
39
- return {
40
- foo: 'bar',
19
+const ReactFeatureFlags = require('shared/ReactFeatureFlags');
20
+
21
+// Once this flag is always true, we should delete this test file
22
+if (ReactFeatureFlags.disableUnstableRenderSubtreeIntoContainer) {
23
+ describe('renderSubtreeIntoContainer', () => {
24
+ it('empty test', () => {
25
+ // Empty test to prevent "Your test suite must contain at least one test." error.
26
+ });
27
+ });
28
+} else {
29
+ describe('renderSubtreeIntoContainer', () => {
30
+ it('should pass context when rendering subtree elsewhere', () => {
31
+ const portal = document.createElement('div');
32
+
33
+ class Component extends React.Component {
34
+ static contextTypes = {
35
+ foo: PropTypes.string.isRequired,
36
};
42
- }
43
-
44
- render() {
45
- return null;
46
- }
37
48
- componentDidMount() {
49
- expect(
50
- function() {
51
- renderSubtreeIntoContainer(this, <Component />, portal);
52
- }.bind(this),
53
- ).not.toThrow();
38
+ render() {
39
+ return <div>{this.context.foo}</div>;
40
+ }
41
}
55
- }
56
-
57
- ReactTestUtils.renderIntoDocument(<Parent />);
58
- expect(portal.firstChild.innerHTML).toBe('bar');
59
- });
60
-
61
- it('should throw if parentComponent is invalid', () => {
62
- const portal = document.createElement('div');
42
64
- class Component extends React.Component {
65
- static contextTypes = {
66
- foo: PropTypes.string.isRequired,
67
- };
68
-
69
- render() {
70
- return <div>{this.context.foo}</div>;
71
- }
72
- }
73
-
74
- // ESLint is confused here and thinks Parent is unused, presumably because
75
- // it is only used inside of the class body?
76
- // eslint-disable-next-line no-unused-vars
77
- class Parent extends React.Component {
78
- static childContextTypes = {
79
- foo: PropTypes.string.isRequired,
80
- };
81
-
82
- getChildContext() {
83
- return {
84
- foo: 'bar',
43
+ class Parent extends React.Component {
44
+ static childContextTypes = {
45
+ foo: PropTypes.string.isRequired,
46
};
86
- }
47
88
- render() {
89
- return null;
90
- }
48
+ getChildContext() {
49
+ return {
50
+ foo: 'bar',
51
+ };
52
+ }
53
+
54
+ render() {
55
+ return null;
56
+ }
57
+
58
+ componentDidMount() {
59
+ expect(
60
+ function() {
61
+ renderSubtreeIntoContainer(this, <Component />, portal);
62
+ }.bind(this),
63
+ ).toWarnDev(
64
+ 'ReactDOM.unstable_renderSubtreeIntoContainer() is deprecated and ' +
65
+ 'will be removed in a future major release. Consider using React Portals instead.',
66
+ );
67
+ }
68
+ }
69
+
70
+ ReactTestUtils.renderIntoDocument(<Parent />);
71
+ expect(portal.firstChild.innerHTML).toBe('bar');
72
+ });
73
+
74
+ it('should throw if parentComponent is invalid', () => {
75
+ const portal = document.createElement('div');
76
+
77
+ class Component extends React.Component {
78
+ static contextTypes = {
79
+ foo: PropTypes.string.isRequired,
80
+ };
81
92
- componentDidMount() {
93
- expect(function() {
94
- renderSubtreeIntoContainer(<Parent />, <Component />, portal);
95
- }).toThrowError('parentComponentmust be a valid React Component');
82
+ render() {
83
+ return <div>{this.context.foo}</div>;
84
+ }
85
}
97
- }
98
- });
99
-
100
- it('should update context if it changes due to setState', () => {
101
- const container = document.createElement('div');
102
- document.body.appendChild(container);
103
- const portal = document.createElement('div');
104
-
105
- class Component extends React.Component {
106
- static contextTypes = {
107
- foo: PropTypes.string.isRequired,
108
- getFoo: PropTypes.func.isRequired,
109
- };
86
111
- render() {
112
- return <div>{this.context.foo + '-' + this.context.getFoo()}</div>;
113
- }
114
- }
115
-
116
- class Parent extends React.Component {
117
- static childContextTypes = {
118
- foo: PropTypes.string.isRequired,
119
- getFoo: PropTypes.func.isRequired,
120
- };
121
-
122
- state = {
123
- bar: 'initial',
124
- };
125
-
126
- getChildContext() {
127
- return {
128
- foo: this.state.bar,
129
- getFoo: () => this.state.bar,
87
+ // ESLint is confused here and thinks Parent is unused, presumably because
88
+ // it is only used inside of the class body?
89
+ // eslint-disable-next-line no-unused-vars
90
+ class Parent extends React.Component {
91
+ static childContextTypes = {
92
+ foo: PropTypes.string.isRequired,
93
};
131
- }
132
-
133
- render() {
134
- return null;
135
- }
94
137
- componentDidMount() {
138
- renderSubtreeIntoContainer(this, <Component />, portal);
139
- }
95
+ getChildContext() {
96
+ return {
97
+ foo: 'bar',
98
+ };
99
+ }
100
+
101
+ render() {
102
+ return null;
103
+ }
104
+
105
+ componentDidMount() {
106
+ expect(function() {
107
+ renderSubtreeIntoContainer(<Parent />, <Component />, portal);
108
+ }).toThrowError('parentComponentmust be a valid React Component');
109
+ }
110
+ }
111
+ });
112
+
113
+ it('should update context if it changes due to setState', () => {
114
+ const container = document.createElement('div');
115
+ document.body.appendChild(container);
116
+ const portal = document.createElement('div');
117
+
118
+ class Component extends React.Component {
119
+ static contextTypes = {
120
+ foo: PropTypes.string.isRequired,
121
+ getFoo: PropTypes.func.isRequired,
122
+ };
123
141
- componentDidUpdate() {
142
- renderSubtreeIntoContainer(this, <Component />, portal);
124
+ render() {
125
+ return <div>{this.context.foo + '-' + this.context.getFoo()}</div>;
126
+ }
127
}
144
- }
145
-
146
- const instance = ReactDOM.render(<Parent />, container);
147
- expect(portal.firstChild.innerHTML).toBe('initial-initial');
148
- instance.setState({bar: 'changed'});
149
- expect(portal.firstChild.innerHTML).toBe('changed-changed');
150
- });
128
152
- it('should update context if it changes due to re-render', () => {
153
- const container = document.createElement('div');
154
- document.body.appendChild(container);
155
- const portal = document.createElement('div');
156
-
157
- class Component extends React.Component {
158
- static contextTypes = {
159
- foo: PropTypes.string.isRequired,
160
- getFoo: PropTypes.func.isRequired,
161
- };
162
-
163
- render() {
164
- return <div>{this.context.foo + '-' + this.context.getFoo()}</div>;
165
- }
166
- }
167
-
168
- class Parent extends React.Component {
169
- static childContextTypes = {
170
- foo: PropTypes.string.isRequired,
171
- getFoo: PropTypes.func.isRequired,
172
- };
173
-
174
- getChildContext() {
175
- return {
176
- foo: this.props.bar,
177
- getFoo: () => this.props.bar,
129
+ class Parent extends React.Component {
130
+ static childContextTypes = {
131
+ foo: PropTypes.string.isRequired,
132
+ getFoo: PropTypes.func.isRequired,
133
};
179
- }
134
181
- render() {
182
- return null;
183
- }
135
+ state = {
136
+ bar: 'initial',
137
+ };
138
185
- componentDidMount() {
186
- renderSubtreeIntoContainer(this, <Component />, portal);
187
- }
139
+ getChildContext() {
140
+ return {
141
+ foo: this.state.bar,
142
+ getFoo: () => this.state.bar,
143
+ };
144
+ }
145
+
146
+ render() {
147
+ return null;
148
+ }
149
+
150
+ componentDidMount() {
151
+ renderSubtreeIntoContainer(this, <Component />, portal);
152
+ }
153
+
154
+ componentDidUpdate() {
155
+ renderSubtreeIntoContainer(this, <Component />, portal);
156
+ }
157
+ }
158
+
159
+ const instance = ReactDOM.render(<Parent />, container);
160
+ expect(portal.firstChild.innerHTML).toBe('initial-initial');
161
+ instance.setState({bar: 'changed'});
162
+ expect(portal.firstChild.innerHTML).toBe('changed-changed');
163
+ });
164
+
165
+ it('should update context if it changes due to re-render', () => {
166
+ const container = document.createElement('div');
167
+ document.body.appendChild(container);
168
+ const portal = document.createElement('div');
169
+
170
+ class Component extends React.Component {
171
+ static contextTypes = {
172
+ foo: PropTypes.string.isRequired,
173
+ getFoo: PropTypes.func.isRequired,
174
+ };
175
189
- componentDidUpdate() {
190
- renderSubtreeIntoContainer(this, <Component />, portal);
176
+ render() {
177
+ return <div>{this.context.foo + '-' + this.context.getFoo()}</div>;
178
+ }
179
}
192
- }
193
-
194
- ReactDOM.render(<Parent bar="initial" />, container);
195
- expect(portal.firstChild.innerHTML).toBe('initial-initial');
196
- ReactDOM.render(<Parent bar="changed" />, container);
197
- expect(portal.firstChild.innerHTML).toBe('changed-changed');
198
- });
180
200
- it('should render portal with non-context-provider parent', () => {
201
- const container = document.createElement('div');
202
- document.body.appendChild(container);
203
- const portal = document.createElement('div');
181
+ class Parent extends React.Component {
182
+ static childContextTypes = {
183
+ foo: PropTypes.string.isRequired,
184
+ getFoo: PropTypes.func.isRequired,
185
+ };
186
205
- class Parent extends React.Component {
206
- render() {
207
- return null;
187
+ getChildContext() {
188
+ return {
189
+ foo: this.props.bar,
190
+ getFoo: () => this.props.bar,
191
+ };
192
+ }
193
+
194
+ render() {
195
+ return null;
196
+ }
197
+
198
+ componentDidMount() {
199
+ renderSubtreeIntoContainer(this, <Component />, portal);
200
+ }
201
+
202
+ componentDidUpdate() {
203
+ renderSubtreeIntoContainer(this, <Component />, portal);
204
+ }
205
+ }
206
+
207
+ ReactDOM.render(<Parent bar="initial" />, container);
208
+ expect(portal.firstChild.innerHTML).toBe('initial-initial');
209
+ ReactDOM.render(<Parent bar="changed" />, container);
210
+ expect(portal.firstChild.innerHTML).toBe('changed-changed');
211
+ });
212
+
213
+ it('should render portal with non-context-provider parent', () => {
214
+ const container = document.createElement('div');
215
+ document.body.appendChild(container);
216
+ const portal = document.createElement('div');
217
+
218
+ class Parent extends React.Component {
219
+ render() {
220
+ return null;
221
+ }
222
+
223
+ componentDidMount() {
224
+ renderSubtreeIntoContainer(this, <div>hello</div>, portal);
225
+ }
226
+ }
227
+
228
+ ReactDOM.render(<Parent bar="initial" />, container);
229
+ expect(portal.firstChild.innerHTML).toBe('hello');
230
+ });
231
+
232
+ it('should get context through non-context-provider parent', () => {
233
+ const container = document.createElement('div');
234
+ document.body.appendChild(container);
235
+ const portal = document.createElement('div');
236
+
237
+ class Parent extends React.Component {
238
+ render() {
239
+ return <Middle />;
240
+ }
241
+ getChildContext() {
242
+ return {value: this.props.value};
243
+ }
244
+ static childContextTypes = {
245
+ value: PropTypes.string.isRequired,
246
+ };
247
}
248
210
- componentDidMount() {
211
- renderSubtreeIntoContainer(this, <div>hello</div>, portal);
249
+ class Middle extends React.Component {
250
+ render() {
251
+ return null;
252
+ }
253
+ componentDidMount() {
254
+ renderSubtreeIntoContainer(this, <Child />, portal);
255
+ }
256
}
213
- }
214
-
215
- ReactDOM.render(<Parent bar="initial" />, container);
216
- expect(portal.firstChild.innerHTML).toBe('hello');
217
- });
218
-
219
- it('should get context through non-context-provider parent', () => {
220
- const container = document.createElement('div');
221
- document.body.appendChild(container);
222
- const portal = document.createElement('div');
257
224
- class Parent extends React.Component {
225
- render() {
226
- return <Middle />;
227
- }
228
- getChildContext() {
229
- return {value: this.props.value};
230
- }
231
- static childContextTypes = {
232
- value: PropTypes.string.isRequired,
233
- };
234
- }
235
-
236
- class Middle extends React.Component {
237
- render() {
238
- return null;
239
- }
240
- componentDidMount() {
241
- renderSubtreeIntoContainer(this, <Child />, portal);
242
- }
243
- }
244
-
245
- class Child extends React.Component {
246
- static contextTypes = {
247
- value: PropTypes.string.isRequired,
248
- };
249
- render() {
250
- return <div>{this.context.value}</div>;
258
+ class Child extends React.Component {
259
+ static contextTypes = {
260
+ value: PropTypes.string.isRequired,
261
+ };
262
+ render() {
263
+ return <div>{this.context.value}</div>;
264
+ }
265
+ }
266
+
267
+ ReactDOM.render(<Parent value="foo" />, container);
268
+ expect(portal.textContent).toBe('foo');
269
+ });
270
+
271
+ it('should get context through middle non-context-provider layer', () => {
272
+ const container = document.createElement('div');
273
+ document.body.appendChild(container);
274
+ const portal1 = document.createElement('div');
275
+ const portal2 = document.createElement('div');
276
+
277
+ class Parent extends React.Component {
278
+ render() {
279
+ return null;
280
+ }
281
+ getChildContext() {
282
+ return {value: this.props.value};
283
+ }
284
+ componentDidMount() {
285
+ renderSubtreeIntoContainer(this, <Middle />, portal1);
286
+ }
287
+ static childContextTypes = {
288
+ value: PropTypes.string.isRequired,
289
+ };
290
}
252
- }
253
-
254
- ReactDOM.render(<Parent value="foo" />, container);
255
- expect(portal.textContent).toBe('foo');
256
- });
257
-
258
- it('should get context through middle non-context-provider layer', () => {
259
- const container = document.createElement('div');
260
- document.body.appendChild(container);
261
- const portal1 = document.createElement('div');
262
- const portal2 = document.createElement('div');
291
264
- class Parent extends React.Component {
265
- render() {
266
- return null;
267
- }
268
- getChildContext() {
269
- return {value: this.props.value};
270
- }
271
- componentDidMount() {
272
- renderSubtreeIntoContainer(this, <Middle />, portal1);
292
+ class Middle extends React.Component {
293
+ render() {
294
+ return null;
295
+ }
296
+ componentDidMount() {
297
+ renderSubtreeIntoContainer(this, <Child />, portal2);
298
+ }
299
}
274
- static childContextTypes = {
275
- value: PropTypes.string.isRequired,
276
- };
277
- }
278
-
279
- class Middle extends React.Component {
280
- render() {
281
- return null;
282
- }
283
- componentDidMount() {
284
- renderSubtreeIntoContainer(this, <Child />, portal2);
285
- }
286
- }
287
-
288
- class Child extends React.Component {
289
- static contextTypes = {
290
- value: PropTypes.string.isRequired,
291
- };
292
- render() {
293
- return <div>{this.context.value}</div>;
294
- }
295
- }
300
297
- ReactDOM.render(<Parent value="foo" />, container);
298
- expect(portal2.textContent).toBe('foo');
299
- });
300
-
301
- it('fails gracefully when mixing React 15 and 16', () => {
302
- class C extends React.Component {
303
- render() {
304
- return <div />;
305
- }
306
- }
307
- const c = ReactDOM.render(<C />, document.createElement('div'));
308
- // React 15 calls this:
309
- // https://github.com/facebook/react/blob/77b71fc3c4/src/renderers/dom/client/ReactMount.js#L478-L479
310
- expect(() => {
311
- c._reactInternalInstance._processChildContext({});
312
- }).toThrow(
313
- __DEV__
314
- ? '_processChildContext is not available in React 16+. This likely ' +
315
- 'means you have multiple copies of React and are attempting to nest ' +
316
- 'a React 15 tree inside a React 16 tree using ' +
317
- "unstable_renderSubtreeIntoContainer, which isn't supported. Try to " +
318
- 'make sure you have only one copy of React (and ideally, switch to ' +
319
- 'ReactDOM.createPortal).'
320
- : "Cannot read property '_processChildContext' of undefined",
321
- );
301
+ class Child extends React.Component {
302
+ static contextTypes = {
303
+ value: PropTypes.string.isRequired,
304
+ };
305
+ render() {
306
+ return <div>{this.context.value}</div>;
307
+ }
308
+ }
309
+
310
+ ReactDOM.render(<Parent value="foo" />, container);
311
+ expect(portal2.textContent).toBe('foo');
312
+ });
313
+
314
+ it('fails gracefully when mixing React 15 and 16', () => {
315
+ class C extends React.Component {
316
+ render() {
317
+ return <div />;
318
+ }
319
+ }
320
+ const c = ReactDOM.render(<C />, document.createElement('div'));
321
+ // React 15 calls this:
322
+ // https://github.com/facebook/react/blob/77b71fc3c4/src/renderers/dom/client/ReactMount.js#L478-L479
323
+ expect(() => {
324
+ c._reactInternalInstance._processChildContext({});
325
+ }).toThrow(
326
+ __DEV__
327
+ ? '_processChildContext is not available in React 16+. This likely ' +
328
+ 'means you have multiple copies of React and are attempting to nest ' +
329
+ 'a React 15 tree inside a React 16 tree using ' +
330
+ "unstable_renderSubtreeIntoContainer, which isn't supported. Try to " +
331
+ 'make sure you have only one copy of React (and ideally, switch to ' +
332
+ 'ReactDOM.createPortal).'
333
+ : "Cannot read property '_processChildContext' of undefined",
334
+ );
335
+ });
336
});
323
-});
337
+}
packages/react-dom/src/client/ReactDOM.js
+41
-19
@@ -53,7 +53,11 @@ import {
53
} from 'legacy-events/EventPropagators';
54
import ReactVersion from 'shared/ReactVersion';
55
import invariant from 'shared/invariant';
56
-import {exposeConcurrentModeAPIs} from 'shared/ReactFeatureFlags';
56
+import {
57
+ exposeConcurrentModeAPIs,
58
+ disableUnstableCreatePortal,
59
+ disableUnstableRenderSubtreeIntoContainer,
60
+} from 'shared/ReactFeatureFlags';
61
62
import {
63
getInstanceFromNode,
@@ -77,6 +81,7 @@ setAttemptContinuousHydration(attemptContinuousHydration);
81
setAttemptHydrationAtCurrentPriority(attemptHydrationAtCurrentPriority);
82
83
let didWarnAboutUnstableCreatePortal = false;
84
+let didWarnAboutUnstableRenderSubtreeIntoContainer = false;
85
86
if (__DEV__) {
87
if (
@@ -129,26 +134,8 @@ const ReactDOM: Object = {
134
findDOMNode,
135
hydrate,
136
render,
132
- unstable_renderSubtreeIntoContainer,
137
unmountComponentAtNode,
138
135
- // Temporary alias since we already shipped React 16 RC with it.
136
- // TODO: remove in React 17.
137
- unstable_createPortal(...args) {
138
- if (__DEV__) {
139
- if (!didWarnAboutUnstableCreatePortal) {
140
- didWarnAboutUnstableCreatePortal = true;
141
- console.warn(
142
- 'The ReactDOM.unstable_createPortal() alias has been deprecated, ' +
143
- 'and will be removed in React 17+. Update your code to use ' +
144
- 'ReactDOM.createPortal() instead. It has the exact same API, ' +
145
- 'but without the "unstable_" prefix.',
146
- );
147
- }
148
- }
149
- return createPortal(...args);
150
- },
151
-
139
unstable_batchedUpdates: batchedUpdates,
140
141
flushSync: flushSync,
@@ -189,6 +176,41 @@ if (exposeConcurrentModeAPIs) {
176
};
177
}
178
179
+if (!disableUnstableRenderSubtreeIntoContainer) {
180
+ ReactDOM.unstable_renderSubtreeIntoContainer = function(...args) {
181
+ if (__DEV__) {
182
+ if (!didWarnAboutUnstableRenderSubtreeIntoContainer) {
183
+ didWarnAboutUnstableRenderSubtreeIntoContainer = true;
184
+ console.warn(
185
+ 'ReactDOM.unstable_renderSubtreeIntoContainer() is deprecated ' +
186
+ 'and will be removed in a future major release. Consider using ' +
187
+ 'React Portals instead.',
188
+ );
189
+ }
190
+ }
191
+ return unstable_renderSubtreeIntoContainer(...args);
192
+ };
193
+}
194
+
195
+if (!disableUnstableCreatePortal) {
196
+ // Temporary alias since we already shipped React 16 RC with it.
197
+ // TODO: remove in React 17.
198
+ ReactDOM.unstable_createPortal = function(...args) {
199
+ if (__DEV__) {
200
+ if (!didWarnAboutUnstableCreatePortal) {
201
+ didWarnAboutUnstableCreatePortal = true;
202
+ console.warn(
203
+ 'The ReactDOM.unstable_createPortal() alias has been deprecated, ' +
204
+ 'and will be removed in React 17+. Update your code to use ' +
205
+ 'ReactDOM.createPortal() instead. It has the exact same API, ' +
206
+ 'but without the "unstable_" prefix.',
207
+ );
208
+ }
209
+ }
210
+ return createPortal(...args);
211
+ };
212
+}
213
+
214
const foundDevTools = injectIntoDevTools({
215
findFiberByHostInstance: getClosestInstanceFromNode,
216
bundleType: __DEV__ ? 1 : 0,
packages/shared/ReactFeatureFlags.js
+6
@@ -108,3 +108,9 @@ export const disableCreateFactory = false;
108
109
// Disables children for <textarea> elements
110
export const disableTextareaChildren = false;
111
+
112
+// Disables ReactDOM.unstable_renderSubtreeIntoContainer
113
+export const disableUnstableRenderSubtreeIntoContainer = false;
114
+
115
+// Disables ReactDOM.unstable_createPortal
116
+export const disableUnstableCreatePortal = false;
packages/shared/forks/ReactFeatureFlags.native-fb.js
+2
@@ -47,6 +47,8 @@ export const enableTrainModelFix = false;
47
export const enableTrustedTypesIntegration = false;
48
export const disableCreateFactory = false;
49
export const disableTextareaChildren = false;
50
+export const disableUnstableRenderSubtreeIntoContainer = false;
51
+export const disableUnstableCreatePortal = false;
52
53
// Only used in www builds.
54
export function addUserTimingListener() {
packages/shared/forks/ReactFeatureFlags.native-oss.js
+2
@@ -42,6 +42,8 @@ export const enableTrustedTypesIntegration = false;
42
export const enableNativeTargetAsInstance = false;
43
export const disableCreateFactory = false;
44
export const disableTextareaChildren = false;
45
+export const disableUnstableRenderSubtreeIntoContainer = false;
46
+export const disableUnstableCreatePortal = false;
47
48
// Only used in www builds.
49
export function addUserTimingListener() {
packages/shared/forks/ReactFeatureFlags.persistent.js
+2
@@ -42,6 +42,8 @@ export const enableTrustedTypesIntegration = false;
42
export const enableNativeTargetAsInstance = false;
43
export const disableCreateFactory = false;
44
export const disableTextareaChildren = false;
45
+export const disableUnstableRenderSubtreeIntoContainer = false;
46
+export const disableUnstableCreatePortal = false;
47
48
// Only used in www builds.
49
export function addUserTimingListener() {
packages/shared/forks/ReactFeatureFlags.test-renderer.js
+2
@@ -42,6 +42,8 @@ export const enableTrustedTypesIntegration = false;
42
export const enableNativeTargetAsInstance = false;
43
export const disableCreateFactory = false;
44
export const disableTextareaChildren = false;
45
+export const disableUnstableRenderSubtreeIntoContainer = false;
46
+export const disableUnstableCreatePortal = false;
47
48
// Only used in www builds.
49
export function addUserTimingListener() {
packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
+2
@@ -40,6 +40,8 @@ export const enableTrustedTypesIntegration = false;
40
export const enableNativeTargetAsInstance = false;
41
export const disableCreateFactory = false;
42
export const disableTextareaChildren = false;
43
+export const disableUnstableRenderSubtreeIntoContainer = false;
44
+export const disableUnstableCreatePortal = false;
45
46
// Only used in www builds.
47
export function addUserTimingListener() {
packages/shared/forks/ReactFeatureFlags.www.js
+4
@@ -94,6 +94,10 @@ export const disableCreateFactory = false;
94
95
export const disableTextareaChildren = false;
96
97
+export const disableUnstableRenderSubtreeIntoContainer = false;
98
+
99
+export const disableUnstableCreatePortal = false;
100
+
101
// Flow magic to verify the exports of this file match the original version.
102
// eslint-disable-next-line no-unused-vars
103
type Check<_X, Y: _X, X: Y = _X> = null;
scripts/flow/config/flowconfig
+1
@@ -30,6 +30,7 @@
30
untyped-type-import=error
31
32
[options]
33
+server.max_workers=4
34
esproposal.class_static_fields=enable
35
esproposal.class_instance_fields=enable
36