Call setState callbacks enqueued in cWM (#8207)
Also fixes return value of ReactNativeMount and moves that callback to be after cDM instead of after all updates.
Ben Alpert committed
Nov 5, 2016 at 14:38 UTC
ef99e7e096cb661de0e72f93a442fbfeaaa07b1c
5 files changed
+66
-45
src/renderers/dom/stack/client/ReactMount.js
+10
-5
@@ -357,7 +357,8 @@ var ReactMount = {
357
nextElement,
358
container,
359
shouldReuseMarkup,
360
- context
360
+ context,
361
+ callback
362
) {
363
// Various parts of our code (such as ReactCompositeComponent's
364
// _renderValidatedComponent) assume that calls to render aren't nested;
@@ -380,6 +381,12 @@ var ReactMount = {
381
ReactBrowserEventEmitter.ensureScrollValueMonitoring();
382
var componentInstance = instantiateReactComponent(nextElement, false);
383
384
+ if (callback) {
385
+ componentInstance._pendingCallbacks = [function() {
386
+ callback.call(componentInstance._renderedComponent.getPublicInstance());
387
+ }];
388
+ }
389
+
390
// The initial render is synchronous but any updates that happen during
391
// rendering, in componentWillMount or componentDidMount, will be batched
392
// according to the current batching strategy.
@@ -529,11 +536,9 @@ var ReactMount = {
536
nextWrappedElement,
537
container,
538
shouldReuseMarkup,
532
- nextContext
539
+ nextContext,
540
+ callback
541
)._renderedComponent.getPublicInstance();
534
- if (callback) {
535
- callback.call(component);
536
- }
542
return component;
543
},
544
src/renderers/native/ReactNativeMount.js
+7
-4
@@ -134,6 +134,12 @@ var ReactNativeMount = {
134
var instance = instantiateReactComponent(nextWrappedElement, false);
135
ReactNativeMount._instancesByContainerID[containerTag] = instance;
136
137
+ if (callback) {
138
+ instance._pendingCallbacks = [function() {
139
+ callback.call(instance._renderedComponent.getPublicInstance());
140
+ }];
141
+ }
142
+
143
// The initial render is synchronous but any updates that happen during
144
// rendering, in componentWillMount or componentDidMount, will be batched
145
// according to the current batching strategy.
@@ -143,10 +149,7 @@ var ReactNativeMount = {
149
instance,
150
containerTag
151
);
146
- var component = instance.getPublicInstance();
147
- if (callback) {
148
- callback.call(component);
149
- }
152
+ var component = instance._renderedComponent.getPublicInstance();
153
return component;
154
},
155
src/renderers/native/__tests__/ReactNativeMount-test.js
+21
@@ -58,4 +58,25 @@ describe('ReactNative', () => {
58
expect(UIManager.updateView).toBeCalledWith(3, 'View', { foo: 'bar' });
59
});
60
61
+ it('should be able to create and update a native component', () => {
62
+ var View = createReactNativeComponentClass({
63
+ validAttributes: { foo: true },
64
+ uiViewClassName: 'View',
65
+ });
66
+
67
+ var a;
68
+ var b;
69
+ var c = ReactNative.render(
70
+ <View foo="foo" ref={(v) => a = v} />,
71
+ 11,
72
+ function() {
73
+ b = this;
74
+ }
75
+ );
76
+
77
+ expect(a).toBeTruthy();
78
+ expect(a).toBe(b);
79
+ expect(a).toBe(c);
80
+ });
81
+
82
});
src/renderers/shared/stack/reconciler/ReactCompositeComponent.js
+12
@@ -383,6 +383,18 @@ var ReactCompositeComponent = {
383
}
384
}
385
386
+ // setState callbacks during willMount should end up here
387
+ const callbacks = this._pendingCallbacks;
388
+ if (callbacks) {
389
+ this._pendingCallbacks = null;
390
+ for (let i = 0; i < callbacks.length; i++) {
391
+ transaction.getReactMountReady().enqueue(
392
+ callbacks[i],
393
+ inst
394
+ );
395
+ }
396
+ }
397
+
398
return markup;
399
},
400
src/renderers/shared/stack/reconciler/__tests__/ReactCompositeComponentState-test.js
+16
-36
@@ -11,8 +11,6 @@
11
12
'use strict';
13
14
-var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
15
-
14
var React;
15
var ReactDOM;
16
@@ -171,40 +169,22 @@ describe('ReactCompositeComponent-state', () => {
169
['componentDidMount-end', 'orange'],
170
];
171
174
- if (ReactDOMFeatureFlags.useFiber) {
175
- // The setState callbacks in componentWillMount, and the initial callback
176
- // passed to ReactDOM.render, should be flushed right after component
177
- // did mount:
178
- expected.push(
179
- ['setState-sunrise', 'orange'], // 1
180
- ['setState-orange', 'orange'], // 2
181
- ['initial-callback', 'orange'], // 3
182
- ['shouldComponentUpdate-currentState', 'orange'],
183
- ['shouldComponentUpdate-nextState', 'yellow'],
184
- ['componentWillUpdate-currentState', 'orange'],
185
- ['componentWillUpdate-nextState', 'yellow'],
186
- ['render', 'yellow'],
187
- ['componentDidUpdate-currentState', 'yellow'],
188
- ['componentDidUpdate-prevState', 'orange'],
189
- ['setState-yellow', 'yellow'],
190
- );
191
- } else {
192
- // There is a bug in the stack reconciler where those callbacks are
193
- // enqueued, but aren't called until the next flush.
194
- expected.push(
195
- ['shouldComponentUpdate-currentState', 'orange'],
196
- ['shouldComponentUpdate-nextState', 'yellow'],
197
- ['componentWillUpdate-currentState', 'orange'],
198
- ['componentWillUpdate-nextState', 'yellow'],
199
- ['render', 'yellow'],
200
- ['componentDidUpdate-currentState', 'yellow'],
201
- ['componentDidUpdate-prevState', 'orange'],
202
- ['setState-sunrise', 'yellow'], // 1
203
- ['setState-orange', 'yellow'], // 2
204
- ['setState-yellow', 'yellow'],
205
- ['initial-callback', 'yellow'] // 3
206
- );
207
- }
172
+ // The setState callbacks in componentWillMount, and the initial callback
173
+ // passed to ReactDOM.render, should be flushed right after component
174
+ // did mount:
175
+ expected.push(
176
+ ['setState-sunrise', 'orange'], // 1
177
+ ['setState-orange', 'orange'], // 2
178
+ ['initial-callback', 'orange'], // 3
179
+ ['shouldComponentUpdate-currentState', 'orange'],
180
+ ['shouldComponentUpdate-nextState', 'yellow'],
181
+ ['componentWillUpdate-currentState', 'orange'],
182
+ ['componentWillUpdate-nextState', 'yellow'],
183
+ ['render', 'yellow'],
184
+ ['componentDidUpdate-currentState', 'yellow'],
185
+ ['componentDidUpdate-prevState', 'orange'],
186
+ ['setState-yellow', 'yellow'],
187
+ );
188
189
expected.push(
190
['componentWillReceiveProps-start', 'yellow'],