47
state = {};
48
componentDidMount() {
49
Scheduler.unstable_yieldValue('commit');
50
- ReactNoop.deferredUpdates(() => {
50
+ React.startTransition(() => {
51
// Has low priority
52
this.setState({b: 'b'});
53
this.setState({c: 'c'});
111
expect(Scheduler).toFlushAndYield(['render', 'componentDidMount']);
112
113
ReactNoop.flushSync(() => {
114
- ReactNoop.deferredUpdates(() => {
114
+ React.startTransition(() => {
115
instance.setState({x: 'x'});
116
instance.setState({y: 'y'});
117
});
118
instance.setState({a: 'a'});
119
instance.setState({b: 'b'});
120
- ReactNoop.deferredUpdates(() => {
120
+ React.startTransition(() => {
121
instance.updater.enqueueReplaceState(instance, {c: 'c'});
122
instance.setState({d: 'd'});
123
});
162
}
163
164
// Schedule some async updates
165
- if (gate(flags => flags.enableSyncDefaultUpdates)) {
165
+ if (
166
+ gate(
167
+ flags => flags.enableSyncDefaultUpdates || flags.enableUnifiedSyncLane,
168
+ )
169
+ ) {
170
React.startTransition(() => {
171
instance.setState(createUpdate('a'));
172
instance.setState(createUpdate('b'));
183
expect(ReactNoop.getChildren()).toEqual([span('')]);
184
185
// Schedule some more updates at different priorities
182
- if (gate(flags => flags.enableSyncDefaultUpdates)) {
183
- instance.setState(createUpdate('d'));
184
- ReactNoop.flushSync(() => {
185
- instance.setState(createUpdate('e'));
186
- instance.setState(createUpdate('f'));
187
- });
188
- React.startTransition(() => {
189
- instance.setState(createUpdate('g'));
190
- });
186
+ instance.setState(createUpdate('d'));
187
+ ReactNoop.flushSync(() => {
188
+ instance.setState(createUpdate('e'));
189
+ instance.setState(createUpdate('f'));
190
+ });
191
+ React.startTransition(() => {
192
+ instance.setState(createUpdate('g'));
193
+ });
194
192
- // The sync updates should have flushed, but not the async ones
195
+ // The sync updates should have flushed, but not the async ones.
196
+ if (
197
+ gate(
198
+ flags => flags.enableSyncDefaultUpdates && flags.enableUnifiedSyncLane,
199
+ )
200
+ ) {
201
+ expect(Scheduler).toHaveYielded(['d', 'e', 'f']);
202
+ expect(ReactNoop.getChildren()).toEqual([span('def')]);
203
+ } else {
204
+ // Update d was dropped and replaced by e.
205
expect(Scheduler).toHaveYielded(['e', 'f']);
206
expect(ReactNoop.getChildren()).toEqual([span('ef')]);
207
+ }
208
196
- // Now flush the remaining work. Even though e and f were already processed,
197
- // they should be processed again, to ensure that the terminal state
198
- // is deterministic.
209
+ // Now flush the remaining work. Even though e and f were already processed,
210
+ // they should be processed again, to ensure that the terminal state
211
+ // is deterministic.
212
+ if (
213
+ gate(
214
+ flags => flags.enableSyncDefaultUpdates && !flags.enableUnifiedSyncLane,
215
+ )
216
+ ) {
217
expect(Scheduler).toFlushAndYield([
218
// Since 'g' is in a transition, we'll process 'd' separately first.
219
// That causes us to process 'd' with 'e' and 'f' rebased.
229
'f',
230
'g',
231
]);
214
- expect(ReactNoop.getChildren()).toEqual([span('abcdefg')]);
232
} else {
216
- instance.setState(createUpdate('d'));
217
- ReactNoop.flushSync(() => {
218
- instance.setState(createUpdate('e'));
219
- instance.setState(createUpdate('f'));
220
- });
221
- instance.setState(createUpdate('g'));
222
-
223
- // The sync updates should have flushed, but not the async ones
224
- expect(Scheduler).toHaveYielded(['e', 'f']);
225
- expect(ReactNoop.getChildren()).toEqual([span('ef')]);
226
-
227
- // Now flush the remaining work. Even though e and f were already processed,
228
- // they should be processed again, to ensure that the terminal state
229
- // is deterministic.
230
- expect(Scheduler).toFlushAndYield(['a', 'b', 'c', 'd', 'e', 'f', 'g']);
231
- expect(ReactNoop.getChildren()).toEqual([span('abcdefg')]);
233
+ expect(Scheduler).toFlushAndYield([
234
+ // Then we'll re-process everything for 'g'.
235
+ 'a',
236
+ 'b',
237
+ 'c',
238
+ 'd',
239
+ 'e',
240
+ 'f',
241
+ 'g',
242
+ ]);
243
}
244
+ expect(ReactNoop.getChildren()).toEqual([span('abcdefg')]);
245
});
246
247
it('can abort an update, schedule a replaceState, and resume', () => {
273
}
274
275
// Schedule some async updates
264
- if (gate(flags => flags.enableSyncDefaultUpdates)) {
276
+ if (
277
+ gate(
278
+ flags => flags.enableSyncDefaultUpdates || flags.enableUnifiedSyncLane,
279
+ )
280
+ ) {
281
React.startTransition(() => {
282
instance.setState(createUpdate('a'));
283
instance.setState(createUpdate('b'));
294
expect(ReactNoop.getChildren()).toEqual([span('')]);
295
296
// Schedule some more updates at different priorities
281
- if (gate(flags => flags.enableSyncDefaultUpdates)) {
282
- instance.setState(createUpdate('d'));
297
+ instance.setState(createUpdate('d'));
298
284
- ReactNoop.flushSync(() => {
285
- instance.setState(createUpdate('e'));
286
- // No longer a public API, but we can test that it works internally by
287
- // reaching into the updater.
288
- instance.updater.enqueueReplaceState(instance, createUpdate('f'));
289
- });
290
- React.startTransition(() => {
291
- instance.setState(createUpdate('g'));
292
- });
299
+ ReactNoop.flushSync(() => {
300
+ instance.setState(createUpdate('e'));
301
+ // No longer a public API, but we can test that it works internally by
302
+ // reaching into the updater.
303
+ instance.updater.enqueueReplaceState(instance, createUpdate('f'));
304
+ });
305
+ React.startTransition(() => {
306
+ instance.setState(createUpdate('g'));
307
+ });
308
294
- // The sync updates should have flushed, but not the async ones.
309
+ // The sync updates should have flushed, but not the async ones.
310
+ if (
311
+ gate(
312
+ flags => flags.enableSyncDefaultUpdates && flags.enableUnifiedSyncLane,
313
+ )
314
+ ) {
315
+ expect(Scheduler).toHaveYielded(['d', 'e', 'f']);
316
+ } else {
317
+ // Update d was dropped and replaced by e.
318
expect(Scheduler).toHaveYielded(['e', 'f']);
296
- expect(ReactNoop.getChildren()).toEqual([span('f')]);
297
-
298
- // Now flush the remaining work. Even though e and f were already processed,
299
- // they should be processed again, to ensure that the terminal state
300
- // is deterministic.
319
+ }
320
+ expect(ReactNoop.getChildren()).toEqual([span('f')]);
321
+
322
+ // Now flush the remaining work. Even though e and f were already processed,
323
+ // they should be processed again, to ensure that the terminal state
324
+ // is deterministic.
325
+ if (
326
+ gate(
327
+ flags => flags.enableSyncDefaultUpdates && !flags.enableUnifiedSyncLane,
328
+ )
329
+ ) {
330
expect(Scheduler).toFlushAndYield([
331
// Since 'g' is in a transition, we'll process 'd' separately first.
332
// That causes us to process 'd' with 'e' and 'f' rebased.
342
'f',
343
'g',
344
]);
316
- expect(ReactNoop.getChildren()).toEqual([span('fg')]);
345
} else {
318
- instance.setState(createUpdate('d'));
319
- ReactNoop.flushSync(() => {
320
- instance.setState(createUpdate('e'));
321
- // No longer a public API, but we can test that it works internally by
322
- // reaching into the updater.
323
- instance.updater.enqueueReplaceState(instance, createUpdate('f'));
324
- });
325
- instance.setState(createUpdate('g'));
326
-
327
- // The sync updates should have flushed, but not the async ones. Update d
328
- // was dropped and replaced by e.
329
- expect(Scheduler).toHaveYielded(['e', 'f']);
330
- expect(ReactNoop.getChildren()).toEqual([span('f')]);
331
-
332
- // Now flush the remaining work. Even though e and f were already processed,
333
- // they should be processed again, to ensure that the terminal state
334
- // is deterministic.
335
- expect(Scheduler).toFlushAndYield(['a', 'b', 'c', 'd', 'e', 'f', 'g']);
336
- expect(ReactNoop.getChildren()).toEqual([span('fg')]);
346
+ expect(Scheduler).toFlushAndYield([
347
+ // Then we'll re-process everything for 'g'.
348
+ 'a',
349
+ 'b',
350
+ 'c',
351
+ 'd',
352
+ 'e',
353
+ 'f',
354
+ 'g',
355
+ ]);
356
}
357
+ expect(ReactNoop.getChildren()).toEqual([span('fg')]);
358
});
359
360
it('passes accumulation of previous updates to replaceState updater function', () => {
708
pushToLog('B'),
709
);
710
});
691
- expect(Scheduler).toHaveYielded([
692
- // A and B are pending. B is higher priority, so we'll render that first.
693
- 'Committed: B',
694
- // Because A comes first in the queue, we're now in rebase mode. B must
695
- // be rebased on top of A. Also, in a layout effect, we received two new
696
- // updates: C and D. C is user-blocking and D is synchronous.
697
- //
698
- // First render the synchronous update. What we're testing here is that
699
- // B *is not dropped* even though it has lower than sync priority. That's
700
- // because we already committed it. However, this render should not
701
- // include C, because that update wasn't already committed.
702
- 'Committed: BD',
703
- 'Committed: BCD',
704
- 'Committed: ABCD',
705
- ]);
711
+ if (gate(flags => flags.enableUnifiedSyncLane)) {
712
+ expect(Scheduler).toHaveYielded([
713
+ 'Committed: B',
714
+ 'Committed: BCD',
715
+ 'Committed: ABCD',
716
+ ]);
717
+ } else {
718
+ expect(Scheduler).toHaveYielded([
719
+ // A and B are pending. B is higher priority, so we'll render that first.
720
+ 'Committed: B',
721
+ // Because A comes first in the queue, we're now in rebase mode. B must
722
+ // be rebased on top of A. Also, in a layout effect, we received two new
723
+ // updates: C and D. C is user-blocking and D is synchronous.
724
+ //
725
+ // First render the synchronous update. What we're testing here is that
726
+ // B *is not dropped* even though it has lower than sync priority. That's
727
+ // because we already committed it. However, this render should not
728
+ // include C, because that update wasn't already committed.
729
+ 'Committed: BD',
730
+ 'Committed: BCD',
731
+ 'Committed: ABCD',
732
+ ]);
733
+ }
734
expect(root).toMatchRenderedOutput('ABCD');
735
});
736
776
pushToLog('B'),
777
);
778
});
751
- expect(Scheduler).toHaveYielded([
752
- // A and B are pending. B is higher priority, so we'll render that first.
753
- 'Committed: B',
754
- // Because A comes first in the queue, we're now in rebase mode. B must
755
- // be rebased on top of A. Also, in a layout effect, we received two new
756
- // updates: C and D. C is user-blocking and D is synchronous.
757
- //
758
- // First render the synchronous update. What we're testing here is that
759
- // B *is not dropped* even though it has lower than sync priority. That's
760
- // because we already committed it. However, this render should not
761
- // include C, because that update wasn't already committed.
762
- 'Committed: BD',
763
- 'Committed: BCD',
764
- 'Committed: ABCD',
765
- ]);
779
+ if (gate(flags => flags.enableUnifiedSyncLane)) {
780
+ expect(Scheduler).toHaveYielded([
781
+ 'Committed: B',
782
+ 'Committed: BCD',
783
+ 'Committed: ABCD',
784
+ ]);
785
+ } else {
786
+ expect(Scheduler).toHaveYielded([
787
+ // A and B are pending. B is higher priority, so we'll render that first.
788
+ 'Committed: B',
789
+ // Because A comes first in the queue, we're now in rebase mode. B must
790
+ // be rebased on top of A. Also, in a layout effect, we received two new
791
+ // updates: C and D. C is user-blocking and D is synchronous.
792
+ //
793
+ // First render the synchronous update. What we're testing here is that
794
+ // B *is not dropped* even though it has lower than sync priority. That's
795
+ // because we already committed it. However, this render should not
796
+ // include C, because that update wasn't already committed.
797
+ 'Committed: BD',
798
+ 'Committed: BCD',
799
+ 'Committed: ABCD',
800
+ ]);
801
+ }
802
expect(root).toMatchRenderedOutput('ABCD');
803
});
804