Remove enableAsyncSubtreeAPI from host config
Use a ReactFeatureFlag instead. It won't be per-renderer, but we likely won't need that. When enableAsyncSubtreeAPI is false, unstable_asyncUpdates is ignored, but does not warn or throw. That way if we discover a bug in async mode, we can flip the flag and revert back to sync without code changes.
Andrew Clark committed
Apr 18, 2017 at 16:38 UTC
9b676a7d0b2160d7301944a1c9d9caec9087e795
8 files changed
+63
-51
scripts/fiber/tests-passing.txt
+3
-3
@@ -751,11 +751,11 @@ src/renderers/dom/fiber/__tests__/ReactDOMFiber-test.js
751
752
src/renderers/dom/fiber/__tests__/ReactDOMFiberAsync-test.js
753
* renders synchronously by default
754
-* throws when calling async APIs when feature flag is disabled
755
-* unstable_asyncUpdates creates an async subtree
756
-* updates inside an async subtree are async by default
754
+* renders syncrhonously when feature flag is disabled
755
* unstable_asyncUpdates at the root makes the entire tree async
756
* updates inside an async tree are async by default
757
+* unstable_asyncUpdates creates an async subtree
758
+* updates inside an async subtree are async by default
759
760
src/renderers/dom/shared/__tests__/CSSProperty-test.js
761
* should generate browser prefixes for its `isUnitlessNumber`
src/renderers/dom/fiber/ReactDOMFiber.js
-1
@@ -364,7 +364,6 @@ var DOMRenderer = ReactFiberReconciler({
364
scheduleDeferredCallback: ReactDOMFrameScheduling.rIC,
365
366
useSyncScheduling: !ReactDOMFeatureFlags.fiberAsyncScheduling,
367
- enableAsyncSubtreeAPI: ReactDOMFeatureFlags.enableAsyncSubtreeAPI,
367
});
368
369
ReactGenericBatching.injection.injectFiberBatchedUpdates(
src/renderers/dom/fiber/__tests__/ReactDOMFiberAsync-test.js
+47
-40
@@ -1,5 +1,6 @@
1
var React = require('react');
2
var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
3
+var ReactFeatureFlags = require('ReactFeatureFlags');
4
5
var ReactDOM;
6
@@ -23,34 +24,62 @@ describe('ReactDOMFiberAsync', () => {
24
});
25
26
if (ReactDOMFeatureFlags.useFiber) {
26
- it('throws when calling async APIs when feature flag is disabled', () => {
27
- expect(() => {
28
- ReactDOM.unstable_asyncRender(<div>Hi</div>, container);
29
- }).toThrow('ReactDOM.unstable_asyncRender is not a function');
27
+ it('renders syncrhonously when feature flag is disabled', () => {
28
+ function Async(props) {
29
+ return props.children;
30
+ }
31
+ Async.unstable_asyncUpdates = true;
32
+ ReactDOM.render(<Async><div>Hi</div></Async>, container);
33
+ expect(container.textContent).toEqual('Hi');
34
+
35
+ ReactDOM.render(<Async><div>Bye</div></Async>, container);
36
+ expect(container.textContent).toEqual('Bye');
37
});
38
39
describe('with feature flag enabled', () => {
40
beforeEach(() => {
41
jest.resetModules();
35
- ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
42
+ ReactFeatureFlags = require('ReactFeatureFlags');
43
container = document.createElement('div');
37
- ReactDOMFeatureFlags.enableAsyncSubtreeAPI = true;
44
+ ReactFeatureFlags.enableAsyncSubtreeAPI = true;
45
ReactDOM = require('react-dom');
46
});
47
41
- it('unstable_asyncUpdates creates an async subtree', () => {
48
+ it('unstable_asyncUpdates at the root makes the entire tree async', () => {
49
+ function Async(props) {
50
+ return props.children;
51
+ }
52
+ Async.unstable_asyncUpdates = true;
53
+ ReactDOM.render(<Async><div>Hi</div></Async>, container);
54
+ expect(container.textContent).toEqual('');
55
+ jest.runAllTimers();
56
+ expect(container.textContent).toEqual('Hi');
57
+
58
+ ReactDOM.render(<Async><div>Bye</div></Async>, container);
59
+ expect(container.textContent).toEqual('Hi');
60
+ jest.runAllTimers();
61
+ expect(container.textContent).toEqual('Bye');
62
+ });
63
+
64
+ it('updates inside an async tree are async by default', () => {
65
+ function Async(props) {
66
+ return props.children;
67
+ }
68
+ Async.unstable_asyncUpdates = true;
69
+
70
let instance;
71
class Component extends React.Component {
72
state = {step: 0};
45
- static unstable_asyncUpdates = true;
73
render() {
74
instance = this;
75
return <div>{this.state.step}</div>;
76
}
77
}
78
52
- ReactDOM.render(<Component />, container);
79
+ ReactDOM.render(<Async><Component /></Async>, container);
80
+ expect(container.textContent).toEqual('');
81
jest.runAllTimers();
82
+ expect(container.textContent).toEqual('0');
83
84
instance.setState({step: 1});
85
expect(container.textContent).toEqual('0');
@@ -58,15 +87,11 @@ describe('ReactDOMFiberAsync', () => {
87
expect(container.textContent).toEqual('1');
88
});
89
61
- it('updates inside an async subtree are async by default', () => {
62
- function Component(props) {
63
- return <Child />;
64
- }
65
- Component.unstable_asyncUpdates = true;
66
-
90
+ it('unstable_asyncUpdates creates an async subtree', () => {
91
let instance;
68
- class Child extends React.Component {
92
+ class Component extends React.Component {
93
state = {step: 0};
94
+ static unstable_asyncUpdates = true;
95
render() {
96
instance = this;
97
return <div>{this.state.step}</div>;
@@ -82,30 +107,14 @@ describe('ReactDOMFiberAsync', () => {
107
expect(container.textContent).toEqual('1');
108
});
109
85
- it('unstable_asyncUpdates at the root makes the entire tree async', () => {
86
- function Async(props) {
87
- return props.children;
88
- }
89
- Async.unstable_asyncUpdates = true;
90
- ReactDOM.render(<Async><div>Hi</div></Async>, container);
91
- expect(container.textContent).toEqual('');
92
- jest.runAllTimers();
93
- expect(container.textContent).toEqual('Hi');
94
-
95
- ReactDOM.render(<Async><div>Bye</div></Async>, container);
96
- expect(container.textContent).toEqual('Hi');
97
- jest.runAllTimers();
98
- expect(container.textContent).toEqual('Bye');
99
- });
100
-
101
- it('updates inside an async tree are async by default', () => {
102
- function Async(props) {
103
- return props.children;
110
+ it('updates inside an async subtree are async by default', () => {
111
+ function Component(props) {
112
+ return <Child />;
113
}
105
- Async.unstable_asyncUpdates = true;
114
+ Component.unstable_asyncUpdates = true;
115
116
let instance;
108
- class Component extends React.Component {
117
+ class Child extends React.Component {
118
state = {step: 0};
119
render() {
120
instance = this;
@@ -113,10 +122,8 @@ describe('ReactDOMFiberAsync', () => {
122
}
123
}
124
116
- ReactDOM.render(<Async><Component /></Async>, container);
117
- expect(container.textContent).toEqual('');
125
+ ReactDOM.render(<Component />, container);
126
jest.runAllTimers();
119
- expect(container.textContent).toEqual('0');
127
128
instance.setState({step: 1});
129
expect(container.textContent).toEqual('0');
src/renderers/dom/shared/ReactDOMFeatureFlags.js
-1
@@ -13,7 +13,6 @@
13
14
var ReactDOMFeatureFlags = {
15
fiberAsyncScheduling: false,
16
- enableAsyncSubtreeAPI: false,
16
useCreateElement: true,
17
useFiber: true,
18
};
src/renderers/shared/fiber/ReactFiber.js
+7
-1
@@ -23,6 +23,8 @@ import type {TypeOfSideEffect} from 'ReactTypeOfSideEffect';
23
import type {PriorityLevel} from 'ReactPriorityLevel';
24
import type {UpdateQueue} from 'ReactFiberUpdateQueue';
25
26
+var ReactFeatureFlags = require('ReactFeatureFlags');
27
+
28
var {
29
IndeterminateComponent,
30
ClassComponent,
@@ -374,7 +376,11 @@ function createFiberFromElementType(
376
internalContextTag: TypeOfInternalContext,
377
debugOwner: null | Fiber | ReactInstance,
378
): Fiber {
377
- if (type != null && (type: any).unstable_asyncUpdates === true) {
379
+ if (
380
+ ReactFeatureFlags.enableAsyncSubtreeAPI &&
381
+ type != null &&
382
+ (type: any).unstable_asyncUpdates === true
383
+ ) {
384
internalContextTag |= AsyncUpdates;
385
}
386
src/renderers/shared/fiber/ReactFiberReconciler.js
+4
-2
@@ -17,6 +17,8 @@ import type {FiberRoot} from 'ReactFiberRoot';
17
import type {PriorityLevel} from 'ReactPriorityLevel';
18
import type {ReactNodeList} from 'ReactTypes';
19
20
+var ReactFeatureFlags = require('ReactFeatureFlags');
21
+
22
var {
23
AsyncUpdates,
24
} = require('ReactTypeOfInternalContext');
@@ -119,7 +121,6 @@ export type HostConfig<T, P, I, TI, PI, C, CX, PL> = {
121
resetAfterCommit(): void,
122
123
useSyncScheduling?: boolean,
122
- enableAsyncSubtreeAPI?: boolean,
124
};
125
126
export type Reconciler<C, I, TI> = {
@@ -189,7 +190,8 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
190
// Check if the top-level element is an async wrapper component. If so, treat
191
// updates to the root as async. This is a bit weird but lets us avoid a separate
192
// `renderAsync` API.
192
- const forceAsync = element != null &&
193
+ const forceAsync = ReactFeatureFlags.enableAsyncSubtreeAPI &&
194
+ element != null &&
195
element.type != null &&
196
(element.type: any).unstable_asyncUpdates === true;
197
const priorityLevel = getPriorityContext(current, forceAsync);
src/renderers/shared/fiber/ReactFiberScheduler.js
+1
-3
@@ -169,7 +169,6 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
169
useSyncScheduling,
170
prepareForCommit,
171
resetAfterCommit,
172
- enableAsyncSubtreeAPI,
172
} = config;
173
174
// The priority level to use when scheduling an update. We use NoWork to
@@ -1353,8 +1352,7 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
1352
if (priorityLevel === NoWork) {
1353
if (
1354
!useSyncScheduling ||
1356
- (enableAsyncSubtreeAPI === true &&
1357
- fiber.internalContextTag & AsyncUpdates) ||
1355
+ fiber.internalContextTag & AsyncUpdates ||
1356
forceAsync
1357
) {
1358
priorityLevel = LowPriority;
src/renderers/shared/utils/ReactFeatureFlags.js
+1
@@ -19,6 +19,7 @@ var ReactFeatureFlags = {
19
logTopLevelRenders: false,
20
prepareNewChildrenBeforeUnmountInStack: true,
21
disableNewFiberFeatures: false,
22
+ enableAsyncSubtreeAPI: false,
23
};
24
25
module.exports = ReactFeatureFlags;