ReactDOM.activeUpdates (#10225)
ReactDOM.flushSync(batch)
Andrew Clark committed
Jul 21, 2017 at 13:22 UTC
0a242554750bb288f88f62e9ed8541597baf9418
13 files changed
+257
-153
scripts/fiber/tests-passing.txt
+4
-1
@@ -682,6 +682,10 @@ src/renderers/dom/fiber/__tests__/ReactDOMFiberAsync-test.js
682
* updates inside an async tree are async by default
683
* AsyncComponent creates an async subtree
684
* updates inside an async subtree are async by default
685
+* flushSync batches sync updates and flushes them at the end of the batch
686
+* flushSync flushes updates even if nested inside another flushSync
687
+* flushSync throws if already performing work
688
+* flushSync flushes updates before end of the tick
689
690
src/renderers/dom/shared/__tests__/CSSProperty-test.js
691
* should generate browser prefixes for its `isUnitlessNumber`
@@ -2160,7 +2164,6 @@ src/renderers/shared/fiber/__tests__/ReactIncremental-test.js
2164
* can call setState inside update callback
2165
* can replaceState
2166
* can forceUpdate
2163
-* performs batched updates at the end of the batch
2167
* can nest batchedUpdates
2168
* can handle if setState callback throws
2169
* merges and masks context
src/renderers/dom/fiber/ReactDOMFiberEntry.js
+2
@@ -742,6 +742,8 @@ var ReactDOMFiber = {
742
743
unstable_deferredUpdates: DOMRenderer.deferredUpdates,
744
745
+ flushSync: DOMRenderer.flushSync,
746
+
747
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: {
748
// For TapEventPlugin which is popular in open source
749
EventPluginHub: require('EventPluginHub'),
src/renderers/dom/fiber/__tests__/ReactDOMFiberAsync-test.js
+145
@@ -134,6 +134,151 @@ describe('ReactDOMFiberAsync', () => {
134
jest.runAllTimers();
135
expect(container.textContent).toEqual('1');
136
});
137
+
138
+ it('flushSync batches sync updates and flushes them at the end of the batch', () => {
139
+ let ops = [];
140
+ let instance;
141
+
142
+ class Component extends React.Component {
143
+ state = {text: ''};
144
+ push(val) {
145
+ this.setState(state => ({text: state.text + val}));
146
+ }
147
+ componentDidUpdate() {
148
+ ops.push(this.state.text);
149
+ }
150
+ render() {
151
+ instance = this;
152
+ return <span>{this.state.text}</span>;
153
+ }
154
+ }
155
+
156
+ ReactDOM.render(<Component />, container);
157
+
158
+ instance.push('A');
159
+ expect(ops).toEqual(['A']);
160
+ expect(container.textContent).toEqual('A');
161
+
162
+ ReactDOM.flushSync(() => {
163
+ instance.push('B');
164
+ instance.push('C');
165
+ // Not flushed yet
166
+ expect(container.textContent).toEqual('A');
167
+ expect(ops).toEqual(['A']);
168
+ });
169
+ expect(container.textContent).toEqual('ABC');
170
+ expect(ops).toEqual(['A', 'ABC']);
171
+ instance.push('D');
172
+ expect(container.textContent).toEqual('ABCD');
173
+ expect(ops).toEqual(['A', 'ABC', 'ABCD']);
174
+ });
175
+
176
+ it('flushSync flushes updates even if nested inside another flushSync', () => {
177
+ let ops = [];
178
+ let instance;
179
+
180
+ class Component extends React.Component {
181
+ state = {text: ''};
182
+ push(val) {
183
+ this.setState(state => ({text: state.text + val}));
184
+ }
185
+ componentDidUpdate() {
186
+ ops.push(this.state.text);
187
+ }
188
+ render() {
189
+ instance = this;
190
+ return <span>{this.state.text}</span>;
191
+ }
192
+ }
193
+
194
+ ReactDOM.render(<Component />, container);
195
+
196
+ instance.push('A');
197
+ expect(ops).toEqual(['A']);
198
+ expect(container.textContent).toEqual('A');
199
+
200
+ ReactDOM.flushSync(() => {
201
+ instance.push('B');
202
+ instance.push('C');
203
+ // Not flushed yet
204
+ expect(container.textContent).toEqual('A');
205
+ expect(ops).toEqual(['A']);
206
+
207
+ ReactDOM.flushSync(() => {
208
+ instance.push('D');
209
+ });
210
+ // The nested flushSync caused everything to flush.
211
+ expect(container.textContent).toEqual('ABCD');
212
+ expect(ops).toEqual(['A', 'ABCD']);
213
+ });
214
+ expect(container.textContent).toEqual('ABCD');
215
+ expect(ops).toEqual(['A', 'ABCD']);
216
+ });
217
+
218
+ it('flushSync throws if already performing work', () => {
219
+ class Component extends React.Component {
220
+ componentDidUpdate() {
221
+ ReactDOM.flushSync(() => {});
222
+ }
223
+ render() {
224
+ return null;
225
+ }
226
+ }
227
+
228
+ // Initial mount
229
+ ReactDOM.render(<Component />, container);
230
+ // Update
231
+ expect(() => ReactDOM.render(<Component />, container)).toThrow(
232
+ 'flushSync was called from inside a lifecycle method',
233
+ );
234
+ });
235
+
236
+ it('flushSync flushes updates before end of the tick', () => {
237
+ let ops = [];
238
+ let instance;
239
+
240
+ class Component extends React.unstable_AsyncComponent {
241
+ state = {text: ''};
242
+ push(val) {
243
+ this.setState(state => ({text: state.text + val}));
244
+ }
245
+ componentDidUpdate() {
246
+ ops.push(this.state.text);
247
+ }
248
+ render() {
249
+ instance = this;
250
+ return <span>{this.state.text}</span>;
251
+ }
252
+ }
253
+
254
+ ReactDOM.render(<Component />, container);
255
+ jest.runAllTimers();
256
+
257
+ // Updates are async by default
258
+ instance.push('A');
259
+ expect(ops).toEqual([]);
260
+ expect(container.textContent).toEqual('');
261
+
262
+ ReactDOM.flushSync(() => {
263
+ instance.push('B');
264
+ instance.push('C');
265
+ // Not flushed yet
266
+ expect(container.textContent).toEqual('');
267
+ expect(ops).toEqual([]);
268
+ });
269
+ // Only the active updates have flushed
270
+ expect(container.textContent).toEqual('BC');
271
+ expect(ops).toEqual(['BC']);
272
+
273
+ instance.push('D');
274
+ expect(container.textContent).toEqual('BC');
275
+ expect(ops).toEqual(['BC']);
276
+
277
+ // Flush the async updates
278
+ jest.runAllTimers();
279
+ expect(container.textContent).toEqual('BCAD');
280
+ expect(ops).toEqual(['BC', 'BCAD']);
281
+ });
282
});
283
}
284
});
src/renderers/native/ReactNativeFiberEntry.js
+2
@@ -89,6 +89,8 @@ const ReactNativeFiber: ReactNativeType = {
89
90
unstable_batchedUpdates: ReactGenericBatching.batchedUpdates,
91
92
+ flushSync: ReactNativeFiberRenderer.flushSync,
93
+
94
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: {
95
// Used as a mixin in many createClass-based components
96
NativeMethodsMixin: require('NativeMethodsMixin'),
src/renderers/noop/ReactNoopEntry.js
+1
-1
@@ -361,7 +361,7 @@ var ReactNoop = {
361
362
unbatchedUpdates: NoopRenderer.unbatchedUpdates,
363
364
- syncUpdates: NoopRenderer.syncUpdates,
364
+ flushSync: NoopRenderer.flushSync,
365
366
// Logs the current state of the tree.
367
dumpTree(rootID: string = DEFAULT_ROOT_ID) {
src/renderers/shared/fiber/ReactFiberReconciler.js
+4
-4
@@ -166,7 +166,7 @@ export type Reconciler<C, I, TI> = {
166
performWithPriority(priorityLevel: PriorityLevel, fn: Function): void,
167
batchedUpdates<A>(fn: () => A): A,
168
unbatchedUpdates<A>(fn: () => A): A,
169
- syncUpdates<A>(fn: () => A): A,
169
+ flushSync<A>(fn: () => A): A,
170
deferredUpdates<A>(fn: () => A): A,
171
172
// Used to extract the return value from the initial render. Legacy API.
@@ -199,7 +199,7 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
199
performWithPriority,
200
batchedUpdates,
201
unbatchedUpdates,
202
- syncUpdates,
202
+ flushSync,
203
deferredUpdates,
204
} = ReactFiberScheduler(config);
205
@@ -290,10 +290,10 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
290
291
unbatchedUpdates,
292
293
- syncUpdates,
294
-
293
deferredUpdates,
294
295
+ flushSync,
296
+
297
getPublicRootInstance(
298
container: OpaqueRoot,
299
): ReactComponent<any, any, any> | PI | null {
src/renderers/shared/fiber/ReactFiberScheduler.js
+13
-3
@@ -1497,13 +1497,23 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
1497
}
1498
}
1499
1500
- function syncUpdates<A>(fn: () => A): A {
1500
+ function flushSync<A>(batch: () => A): A {
1501
+ const previousIsBatchingUpdates = isBatchingUpdates;
1502
const previousPriorityContext = priorityContext;
1503
+ isBatchingUpdates = true;
1504
priorityContext = SynchronousPriority;
1505
try {
1504
- return fn();
1506
+ return batch();
1507
} finally {
1508
+ isBatchingUpdates = previousIsBatchingUpdates;
1509
priorityContext = previousPriorityContext;
1510
+
1511
+ invariant(
1512
+ !isPerformingWork,
1513
+ 'flushSync was called from inside a lifecycle method. It cannot be ' +
1514
+ 'called when React is already rendering.',
1515
+ );
1516
+ performWork(TaskPriority, null);
1517
}
1518
}
1519
@@ -1523,7 +1533,7 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
1533
performWithPriority: performWithPriority,
1534
batchedUpdates: batchedUpdates,
1535
unbatchedUpdates: unbatchedUpdates,
1526
- syncUpdates: syncUpdates,
1536
+ flushSync: flushSync,
1537
deferredUpdates: deferredUpdates,
1538
};
1539
};
src/renderers/shared/fiber/__tests__/ReactIncremental-test.js
+4
-42
@@ -326,7 +326,7 @@ describe('ReactIncremental', () => {
326
}
327
328
// Init
329
- ReactNoop.syncUpdates(() => {
329
+ ReactNoop.flushSync(() => {
330
ReactNoop.render(<Foo text="foo" />);
331
});
332
ReactNoop.flush();
@@ -335,7 +335,7 @@ describe('ReactIncremental', () => {
335
ops = [];
336
337
// Render the high priority work (everying except the hidden trees).
338
- ReactNoop.syncUpdates(() => {
338
+ ReactNoop.flushSync(() => {
339
ReactNoop.render(<Foo text="foo" />);
340
});
341
expect(ops).toEqual(['Foo', 'Bar', 'Bar']);
@@ -773,7 +773,7 @@ describe('ReactIncremental', () => {
773
// Interrupt the current low pri work with a high pri update elsewhere in
774
// the tree.
775
ops = [];
776
- ReactNoop.syncUpdates(() => {
776
+ ReactNoop.flushSync(() => {
777
sibling.setState({});
778
});
779
expect(ops).toEqual(['Sibling']);
@@ -1661,42 +1661,6 @@ describe('ReactIncremental', () => {
1661
},
1662
);
1663
1664
- it('performs batched updates at the end of the batch', () => {
1665
- var ops = [];
1666
- var instance;
1667
-
1668
- class Foo extends React.Component {
1669
- state = {n: 0};
1670
- render() {
1671
- instance = this;
1672
- return <div />;
1673
- }
1674
- }
1675
-
1676
- ReactNoop.render(<Foo />);
1677
- ReactNoop.flush();
1678
- ops = [];
1679
-
1680
- ReactNoop.syncUpdates(() => {
1681
- ReactNoop.batchedUpdates(() => {
1682
- instance.setState({n: 1}, () => ops.push('setState 1'));
1683
- instance.setState({n: 2}, () => ops.push('setState 2'));
1684
- ops.push('end batchedUpdates');
1685
- });
1686
- ops.push('end syncUpdates');
1687
- });
1688
-
1689
- // ReactNoop.flush() not needed because updates are synchronous
1690
-
1691
- expect(ops).toEqual([
1692
- 'end batchedUpdates',
1693
- 'setState 1',
1694
- 'setState 2',
1695
- 'end syncUpdates',
1696
- ]);
1697
- expect(instance.state.n).toEqual(2);
1698
- });
1699
-
1664
it('can nest batchedUpdates', () => {
1665
var ops = [];
1666
var instance;
@@ -1713,7 +1677,7 @@ describe('ReactIncremental', () => {
1677
ReactNoop.flush();
1678
ops = [];
1679
1716
- ReactNoop.syncUpdates(() => {
1680
+ ReactNoop.flushSync(() => {
1681
ReactNoop.batchedUpdates(() => {
1682
instance.setState({n: 1}, () => ops.push('setState 1'));
1683
instance.setState({n: 2}, () => ops.push('setState 2'));
@@ -1724,7 +1688,6 @@ describe('ReactIncremental', () => {
1688
});
1689
ops.push('end outer batchedUpdates');
1690
});
1727
- ops.push('end syncUpdates');
1691
});
1692
1693
// ReactNoop.flush() not needed because updates are synchronous
@@ -1736,7 +1699,6 @@ describe('ReactIncremental', () => {
1699
'setState 2',
1700
'setState 3',
1701
'setState 4',
1739
- 'end syncUpdates',
1702
]);
1703
expect(instance.state.n).toEqual(4);
1704
});
src/renderers/shared/fiber/__tests__/ReactIncrementalErrorHandling-test.js
+25
-29
@@ -134,7 +134,7 @@ describe('ReactIncrementalErrorHandling', () => {
134
throw new Error('Hello');
135
}
136
137
- ReactNoop.syncUpdates(() => {
137
+ ReactNoop.flushSync(() => {
138
ReactNoop.render(
139
<ErrorBoundary>
140
<BrokenRender />
@@ -176,19 +176,17 @@ describe('ReactIncrementalErrorHandling', () => {
176
throw new Error('Hello');
177
}
178
179
- ReactNoop.syncUpdates(() => {
180
- ReactNoop.batchedUpdates(() => {
181
- ReactNoop.render(
182
- <ErrorBoundary>
183
- Before the storm.
184
- </ErrorBoundary>,
185
- );
186
- ReactNoop.render(
187
- <ErrorBoundary>
188
- <BrokenRender />
189
- </ErrorBoundary>,
190
- );
191
- });
179
+ ReactNoop.flushSync(() => {
180
+ ReactNoop.render(
181
+ <ErrorBoundary>
182
+ Before the storm.
183
+ </ErrorBoundary>,
184
+ );
185
+ ReactNoop.render(
186
+ <ErrorBoundary>
187
+ <BrokenRender />
188
+ </ErrorBoundary>,
189
+ );
190
});
191
192
expect(ops).toEqual([
@@ -292,7 +290,7 @@ describe('ReactIncrementalErrorHandling', () => {
290
}
291
292
expect(() => {
295
- ReactNoop.syncUpdates(() => {
293
+ ReactNoop.flushSync(() => {
294
ReactNoop.render(
295
<RethrowErrorBoundary>
296
<BrokenRender />
@@ -327,19 +325,17 @@ describe('ReactIncrementalErrorHandling', () => {
325
}
326
327
expect(() => {
330
- ReactNoop.syncUpdates(() => {
331
- ReactNoop.batchedUpdates(() => {
332
- ReactNoop.render(
333
- <RethrowErrorBoundary>
334
- Before the storm.
335
- </RethrowErrorBoundary>,
336
- );
337
- ReactNoop.render(
338
- <RethrowErrorBoundary>
339
- <BrokenRender />
340
- </RethrowErrorBoundary>,
341
- );
342
- });
328
+ ReactNoop.flushSync(() => {
329
+ ReactNoop.render(
330
+ <RethrowErrorBoundary>
331
+ Before the storm.
332
+ </RethrowErrorBoundary>,
333
+ );
334
+ ReactNoop.render(
335
+ <RethrowErrorBoundary>
336
+ <BrokenRender />
337
+ </RethrowErrorBoundary>,
338
+ );
339
});
340
}).toThrow('Hello');
341
expect(ops).toEqual([
@@ -383,7 +379,7 @@ describe('ReactIncrementalErrorHandling', () => {
379
it('applies sync updates regardless despite errors in scheduling', () => {
380
ReactNoop.render(<span prop="a:1" />);
381
expect(() => {
386
- ReactNoop.syncUpdates(() => {
382
+ ReactNoop.flushSync(() => {
383
ReactNoop.batchedUpdates(() => {
384
ReactNoop.render(<span prop="a:2" />);
385
ReactNoop.render(<span prop="a:3" />);
src/renderers/shared/fiber/__tests__/ReactIncrementalPerf-test.js
+2
-2
@@ -282,7 +282,7 @@ describe('ReactDebugFiberPerf', () => {
282
283
it('measures deprioritized work', () => {
284
addComment('Flush the parent');
285
- ReactNoop.syncUpdates(() => {
285
+ ReactNoop.flushSync(() => {
286
ReactNoop.render(
287
<Parent>
288
<div hidden={true}>
@@ -498,7 +498,7 @@ describe('ReactDebugFiberPerf', () => {
498
return <span prop={this.state.step} />;
499
}
500
}
501
- ReactNoop.syncUpdates(() => {
501
+ ReactNoop.flushSync(() => {
502
ReactNoop.render(<Component />);
503
});
504
expect(getFlameChart()).toMatchSnapshot();
src/renderers/shared/fiber/__tests__/ReactIncrementalScheduling-test.js
+20
-24
@@ -56,7 +56,7 @@ describe('ReactIncrementalScheduling', () => {
56
57
ReactNoop.batchedUpdates(() => {
58
ReactNoop.render(<span prop={5} />);
59
- ReactNoop.syncUpdates(() => {
59
+ ReactNoop.flushSync(() => {
60
ReactNoop.render(<span prop={2} />);
61
ReactNoop.render(<span prop={3} />);
62
ReactNoop.render(<span prop={4} />);
@@ -213,7 +213,7 @@ describe('ReactIncrementalScheduling', () => {
213
}
214
}
215
216
- ReactNoop.syncUpdates(() => {
216
+ ReactNoop.flushSync(() => {
217
ReactNoop.render(<Foo />);
218
});
219
// The cDM update should not have flushed yet because it has async priority.
@@ -268,29 +268,25 @@ describe('ReactIncrementalScheduling', () => {
268
});
269
270
it('can opt-out of batching using unbatchedUpdates', () => {
271
- // syncUpdates gives synchronous priority to updates
272
- ReactNoop.syncUpdates(() => {
273
- // batchedUpdates downgrades sync updates to task priority
274
- ReactNoop.batchedUpdates(() => {
275
- ReactNoop.render(<span prop={0} />);
276
- expect(ReactNoop.getChildren()).toEqual([]);
277
- // Should not have flushed yet because we're still batching
278
-
279
- // unbatchedUpdates reverses the effect of batchedUpdates, so sync
280
- // updates are not batched
281
- ReactNoop.unbatchedUpdates(() => {
282
- ReactNoop.render(<span prop={1} />);
283
- expect(ReactNoop.getChildren()).toEqual([span(1)]);
284
- ReactNoop.render(<span prop={2} />);
285
- expect(ReactNoop.getChildren()).toEqual([span(2)]);
286
- });
287
-
288
- ReactNoop.render(<span prop={3} />);
271
+ ReactNoop.flushSync(() => {
272
+ ReactNoop.render(<span prop={0} />);
273
+ expect(ReactNoop.getChildren()).toEqual([]);
274
+ // Should not have flushed yet because we're still batching
275
+
276
+ // unbatchedUpdates reverses the effect of batchedUpdates, so sync
277
+ // updates are not batched
278
+ ReactNoop.unbatchedUpdates(() => {
279
+ ReactNoop.render(<span prop={1} />);
280
+ expect(ReactNoop.getChildren()).toEqual([span(1)]);
281
+ ReactNoop.render(<span prop={2} />);
282
expect(ReactNoop.getChildren()).toEqual([span(2)]);
283
});
291
- // Remaining update is now flushed
292
- expect(ReactNoop.getChildren()).toEqual([span(3)]);
284
+
285
+ ReactNoop.render(<span prop={3} />);
286
+ expect(ReactNoop.getChildren()).toEqual([span(2)]);
287
});
288
+ // Remaining update is now flushed
289
+ expect(ReactNoop.getChildren()).toEqual([span(3)]);
290
});
291
292
it('nested updates are always deferred, even inside unbatchedUpdates', () => {
@@ -320,10 +316,10 @@ describe('ReactIncrementalScheduling', () => {
316
ReactNoop.flush();
317
expect(ReactNoop.getChildren()).toEqual([span(0)]);
318
323
- ReactNoop.syncUpdates(() => {
319
+ ReactNoop.flushSync(() => {
320
instance.setState({step: 1});
325
- expect(ReactNoop.getChildren()).toEqual([span(2)]);
321
});
322
+ expect(ReactNoop.getChildren()).toEqual([span(2)]);
323
324
expect(ops).toEqual([
325
'render: 0',
src/renderers/shared/fiber/__tests__/ReactIncrementalTriangle-test.js
+8
-12
@@ -79,17 +79,13 @@ describe('ReactIncrementalTriangle', () => {
79
if (this.props.depth !== 0) {
80
throw new Error('Cannot activate non-leaf component');
81
}
82
- ReactNoop.syncUpdates(() => {
83
- this.setState({isActive: true});
84
- });
82
+ this.setState({isActive: true});
83
}
84
deactivate() {
85
if (this.props.depth !== 0) {
86
throw new Error('Cannot deactivate non-leaf component');
87
}
90
- ReactNoop.syncUpdates(() => {
91
- this.setState({isActive: false});
92
- });
88
+ this.setState({isActive: false});
89
}
90
shouldComponentUpdate(nextProps, nextState) {
91
return (
@@ -121,9 +117,7 @@ describe('ReactIncrementalTriangle', () => {
117
state = {counter: 0};
118
interrupt() {
119
// Triggers a restart from the top.
124
- ReactNoop.syncUpdates(() => {
125
- this.forceUpdate();
126
- });
120
+ this.forceUpdate();
121
}
122
setCounter(counter) {
123
const currentCounter = this.state.counter;
@@ -193,15 +187,17 @@ describe('ReactIncrementalTriangle', () => {
187
188
let activeTriangle = null;
189
for (var i = 0; i < actions.length; i++) {
196
- ReactNoop.batchedUpdates(() => {
190
+ ReactNoop.flushSync(() => {
191
const action = actions[i];
192
switch (action.type) {
193
case FLUSH:
194
ReactNoop.flushUnitsOfWork(action.unitsOfWork);
195
break;
196
case STEP:
203
- app.setCounter(action.counter);
204
- expectedCounterAtEnd = action.counter;
197
+ ReactNoop.deferredUpdates(() => {
198
+ app.setCounter(action.counter);
199
+ expectedCounterAtEnd = action.counter;
200
+ });
201
break;
202
case INTERRUPT:
203
app.interrupt();
src/renderers/shared/fiber/__tests__/ReactIncrementalUpdates-test.js
+27
-35
@@ -96,18 +96,16 @@ describe('ReactIncrementalUpdates', () => {
96
ReactNoop.render(<Foo />);
97
ReactNoop.flush();
98
99
- ReactNoop.syncUpdates(() => {
100
- ReactNoop.batchedUpdates(() => {
101
- ReactNoop.deferredUpdates(() => {
102
- instance.setState({x: 'x'});
103
- instance.setState({y: 'y'});
104
- });
105
- instance.setState({a: 'a'});
106
- instance.setState({b: 'b'});
107
- ReactNoop.deferredUpdates(() => {
108
- instance.updater.enqueueReplaceState(instance, {c: 'c'});
109
- instance.setState({d: 'd'});
110
- });
99
+ ReactNoop.flushSync(() => {
100
+ ReactNoop.deferredUpdates(() => {
101
+ instance.setState({x: 'x'});
102
+ instance.setState({y: 'y'});
103
+ });
104
+ instance.setState({a: 'a'});
105
+ instance.setState({b: 'b'});
106
+ ReactNoop.deferredUpdates(() => {
107
+ instance.updater.enqueueReplaceState(instance, {c: 'c'});
108
+ instance.setState({d: 'd'});
109
});
110
});
111
@@ -160,15 +158,13 @@ describe('ReactIncrementalUpdates', () => {
158
ReactNoop.flushThrough(['a', 'b', 'c']);
159
expect(ReactNoop.getChildren()).toEqual([span('')]);
160
163
- // Schedule some more updates at different priorities
164
- ReactNoop.batchedUpdates(() => {
165
- instance.setState(createUpdate('f'));
166
- ReactNoop.syncUpdates(() => {
167
- instance.setState(createUpdate('d'));
168
- instance.setState(createUpdate('e'));
169
- });
170
- instance.setState(createUpdate('g'));
161
+ // Schedule some more updates at different priorities{
162
+ instance.setState(createUpdate('f'));
163
+ ReactNoop.flushSync(() => {
164
+ instance.setState(createUpdate('d'));
165
+ instance.setState(createUpdate('e'));
166
});
167
+ instance.setState(createUpdate('g'));
168
169
// The sync updates should have flushed, but not the async ones
170
expect(ReactNoop.getChildren()).toEqual([span('de')]);
@@ -210,17 +206,15 @@ describe('ReactIncrementalUpdates', () => {
206
ReactNoop.flushThrough(['a', 'b', 'c']);
207
expect(ReactNoop.getChildren()).toEqual([span('')]);
208
213
- // Schedule some more updates at different priorities
214
- ReactNoop.batchedUpdates(() => {
215
- instance.setState(createUpdate('f'));
216
- ReactNoop.syncUpdates(() => {
217
- instance.setState(createUpdate('d'));
218
- // No longer a public API, but we can test that it works internally by
219
- // reaching into the updater.
220
- instance.updater.enqueueReplaceState(instance, createUpdate('e'));
221
- });
222
- instance.setState(createUpdate('g'));
209
+ // Schedule some more updates at different priorities{
210
+ instance.setState(createUpdate('f'));
211
+ ReactNoop.flushSync(() => {
212
+ instance.setState(createUpdate('d'));
213
+ // No longer a public API, but we can test that it works internally by
214
+ // reaching into the updater.
215
+ instance.updater.enqueueReplaceState(instance, createUpdate('e'));
216
});
217
+ instance.setState(createUpdate('g'));
218
219
// The sync updates should have flushed, but not the async ones. Update d
220
// was dropped and replaced by e.
@@ -307,11 +301,9 @@ describe('ReactIncrementalUpdates', () => {
301
302
ops = [];
303
310
- ReactNoop.batchedUpdates(() => {
311
- ReactNoop.syncUpdates(() => {
312
- instance.setState({a: 'a'});
313
- ReactNoop.render(<Foo />); // Trigger componentWillReceiveProps
314
- });
304
+ ReactNoop.flushSync(() => {
305
+ instance.setState({a: 'a'});
306
+ ReactNoop.render(<Foo />); // Trigger componentWillReceiveProps
307
});
308
309
expect(instance.state).toEqual({a: 'a', b: 'b'});