React.unstable_AsyncComponent (#10239)
Alternative to using the static class property unstable_asyncUpdates. Everything inside <AsyncComponent /> has async updates by default. You can also extend it like PureComponent or Component.
Andrew Clark committed
Jul 20, 2017 at 18:00 UTC
ae430b79139777b74167b124719b3dc311aa5294
6 files changed
+57
-38
scripts/fiber/tests-passing.txt
+2
-2
@@ -674,9 +674,9 @@ src/renderers/dom/fiber/__tests__/ReactDOMFiber-test.js
674
src/renderers/dom/fiber/__tests__/ReactDOMFiberAsync-test.js
675
* renders synchronously by default
676
* renders synchronously when feature flag is disabled
677
-* unstable_asyncUpdates at the root makes the entire tree async
677
+* AsyncComponent at the root makes the entire tree async
678
* updates inside an async tree are async by default
679
-* unstable_asyncUpdates creates an async subtree
679
+* AsyncComponent creates an async subtree
680
* updates inside an async subtree are async by default
681
682
src/renderers/dom/shared/__tests__/CSSProperty-test.js
src/isomorphic/ReactEntry.js
+1
@@ -40,6 +40,7 @@ var React = {
40
41
Component: ReactBaseClasses.Component,
42
PureComponent: ReactBaseClasses.PureComponent,
43
+ unstable_AsyncComponent: ReactBaseClasses.AsyncComponent,
44
45
createElement: createElement,
46
cloneElement: cloneElement,
src/isomorphic/modern/class/ReactBaseClasses.js
+24
-4
@@ -138,13 +138,33 @@ function ReactPureComponent(props, context, updater) {
138
139
function ComponentDummy() {}
140
ComponentDummy.prototype = ReactComponent.prototype;
141
-ReactPureComponent.prototype = new ComponentDummy();
142
-ReactPureComponent.prototype.constructor = ReactPureComponent;
141
+var pureComponentPrototype = (ReactPureComponent.prototype = new ComponentDummy());
142
+pureComponentPrototype.constructor = ReactPureComponent;
143
// Avoid an extra prototype jump for these methods.
144
-Object.assign(ReactPureComponent.prototype, ReactComponent.prototype);
145
-ReactPureComponent.prototype.isPureReactComponent = true;
144
+Object.assign(pureComponentPrototype, ReactComponent.prototype);
145
+pureComponentPrototype.isPureReactComponent = true;
146
+
147
+function ReactAsyncComponent(props, context, updater) {
148
+ // Duplicated from ReactComponent.
149
+ this.props = props;
150
+ this.context = context;
151
+ this.refs = emptyObject;
152
+ // We initialize the default updater but the real one gets injected by the
153
+ // renderer.
154
+ this.updater = updater || ReactNoopUpdateQueue;
155
+}
156
+
157
+var asyncComponentPrototype = (ReactAsyncComponent.prototype = new ComponentDummy());
158
+asyncComponentPrototype.constructor = ReactAsyncComponent;
159
+// Avoid an extra prototype jump for these methods.
160
+Object.assign(asyncComponentPrototype, ReactComponent.prototype);
161
+asyncComponentPrototype.unstable_isAsyncReactComponent = true;
162
+asyncComponentPrototype.render = function() {
163
+ return this.props.children;
164
+};
165
166
module.exports = {
167
Component: ReactComponent,
168
PureComponent: ReactPureComponent,
169
+ AsyncComponent: ReactAsyncComponent,
170
};
src/renderers/dom/fiber/__tests__/ReactDOMFiberAsync-test.js
+26
-30
@@ -4,6 +4,8 @@ var ReactFeatureFlags = require('ReactFeatureFlags');
4
5
var ReactDOM;
6
7
+var AsyncComponent = React.unstable_AsyncComponent;
8
+
9
describe('ReactDOMFiberAsync', () => {
10
var container;
11
@@ -25,16 +27,16 @@ describe('ReactDOMFiberAsync', () => {
27
28
if (ReactDOMFeatureFlags.useFiber) {
29
it('renders synchronously when feature flag is disabled', () => {
28
- class Async extends React.Component {
29
- static unstable_asyncUpdates = true;
30
- render() {
31
- return this.props.children;
32
- }
33
- }
34
- ReactDOM.render(<Async><div>Hi</div></Async>, container);
30
+ ReactDOM.render(
31
+ <AsyncComponent><div>Hi</div></AsyncComponent>,
32
+ container,
33
+ );
34
expect(container.textContent).toEqual('Hi');
35
37
- ReactDOM.render(<Async><div>Bye</div></Async>, container);
36
+ ReactDOM.render(
37
+ <AsyncComponent><div>Bye</div></AsyncComponent>,
38
+ container,
39
+ );
40
expect(container.textContent).toEqual('Bye');
41
});
42
@@ -47,32 +49,25 @@ describe('ReactDOMFiberAsync', () => {
49
ReactDOM = require('react-dom');
50
});
51
50
- it('unstable_asyncUpdates at the root makes the entire tree async', () => {
51
- class Async extends React.Component {
52
- static unstable_asyncUpdates = true;
53
- render() {
54
- return this.props.children;
55
- }
56
- }
57
- ReactDOM.render(<Async><div>Hi</div></Async>, container);
52
+ it('AsyncComponent at the root makes the entire tree async', () => {
53
+ ReactDOM.render(
54
+ <AsyncComponent><div>Hi</div></AsyncComponent>,
55
+ container,
56
+ );
57
expect(container.textContent).toEqual('');
58
jest.runAllTimers();
59
expect(container.textContent).toEqual('Hi');
60
62
- ReactDOM.render(<Async><div>Bye</div></Async>, container);
61
+ ReactDOM.render(
62
+ <AsyncComponent><div>Bye</div></AsyncComponent>,
63
+ container,
64
+ );
65
expect(container.textContent).toEqual('Hi');
66
jest.runAllTimers();
67
expect(container.textContent).toEqual('Bye');
68
});
69
70
it('updates inside an async tree are async by default', () => {
69
- class Async extends React.Component {
70
- static unstable_asyncUpdates = true;
71
- render() {
72
- return this.props.children;
73
- }
74
- }
75
-
71
let instance;
72
class Component extends React.Component {
73
state = {step: 0};
@@ -82,7 +77,10 @@ describe('ReactDOMFiberAsync', () => {
77
}
78
}
79
85
- ReactDOM.render(<Async><Component /></Async>, container);
80
+ ReactDOM.render(
81
+ <AsyncComponent><Component /></AsyncComponent>,
82
+ container,
83
+ );
84
expect(container.textContent).toEqual('');
85
jest.runAllTimers();
86
expect(container.textContent).toEqual('0');
@@ -93,11 +91,10 @@ describe('ReactDOMFiberAsync', () => {
91
expect(container.textContent).toEqual('1');
92
});
93
96
- it('unstable_asyncUpdates creates an async subtree', () => {
94
+ it('AsyncComponent creates an async subtree', () => {
95
let instance;
98
- class Component extends React.Component {
96
+ class Component extends React.unstable_AsyncComponent {
97
state = {step: 0};
100
- static unstable_asyncUpdates = true;
98
render() {
99
instance = this;
100
return <div>{this.state.step}</div>;
@@ -114,8 +111,7 @@ describe('ReactDOMFiberAsync', () => {
111
});
112
113
it('updates inside an async subtree are async by default', () => {
117
- class Component extends React.Component {
118
- static unstable_asyncUpdates = true;
114
+ class Component extends React.unstable_AsyncComponent {
115
render() {
116
return <Child />;
117
}
src/renderers/shared/fiber/ReactFiberClassComponent.js
+2
-1
@@ -388,7 +388,8 @@ module.exports = function(
388
if (
389
ReactFeatureFlags.enableAsyncSubtreeAPI &&
390
workInProgress.type != null &&
391
- workInProgress.type.unstable_asyncUpdates === true
391
+ workInProgress.type.prototype != null &&
392
+ workInProgress.type.prototype.unstable_isAsyncReactComponent === true
393
) {
394
workInProgress.internalContextTag |= AsyncUpdates;
395
}
src/renderers/shared/fiber/ReactFiberReconciler.js
+2
-1
@@ -225,7 +225,8 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
225
ReactFeatureFlags.enableAsyncSubtreeAPI &&
226
element != null &&
227
element.type != null &&
228
- (element.type: any).unstable_asyncUpdates === true;
228
+ element.type.prototype != null &&
229
+ (element.type.prototype: any).unstable_isAsyncReactComponent === true;
230
const priorityLevel = getPriorityContext(current, forceAsync);
231
const nextState = {element};
232
callback = callback === undefined ? null : callback;