@@ -16,6 +16,7 @@ import type {Fiber} from './ReactFiber';
16
16
import type { ExpirationTime } from './ReactFiberExpirationTime' ;
17
17
import type { HookEffectTag } from './ReactHookEffectTags' ;
18
18
import type { SuspenseConfig } from './ReactFiberSuspenseConfig' ;
19
+ import type { TransitionInstance } from './ReactFiberTransition' ;
19
20
import type { ReactPriorityLevel } from './SchedulerWithReactIntegration' ;
20
21
21
22
import ReactSharedInternals from 'shared/ReactSharedInternals' ;
@@ -51,11 +52,11 @@ import is from 'shared/objectIs';
51
52
import { markWorkInProgressReceivedUpdate } from './ReactFiberBeginWork' ;
52
53
import { requestCurrentSuspenseConfig } from './ReactFiberSuspenseConfig' ;
53
54
import {
54
- UserBlockingPriority ,
55
- NormalPriority ,
56
- runWithPriority ,
57
- getCurrentPriorityLevel ,
58
- } from './SchedulerWithReactIntegration' ;
55
+ startTransition ,
56
+ requestCurrentTransition ,
57
+ cancelPendingTransition ,
58
+ } from './ReactFiberTransition' ;
59
+ import { getCurrentPriorityLevel } from './SchedulerWithReactIntegration' ;
59
60
60
61
const { ReactCurrentDispatcher, ReactCurrentBatchConfig} = ReactSharedInternals ;
61
62
@@ -114,14 +115,11 @@ type Update<S, A> = {|
114
115
type UpdateQueue < S , A > = { |
115
116
pending : Update < S , A > | null ,
116
117
dispatch : ( A => mixed ) | null ,
118
+ pendingTransition : TransitionInstance | null ,
117
119
lastRenderedReducer : ( ( S , A ) => S ) | null ,
118
120
lastRenderedState : S | null ,
119
121
| } ;
120
122
121
- type TransitionInstance = { |
122
- pendingExpirationTime : ExpirationTime ,
123
- | } ;
124
-
125
123
export type HookType =
126
124
| 'useState '
127
125
| 'useReducer '
@@ -646,6 +644,7 @@ function mountReducer<S, I, A>(
646
644
const queue = ( hook . queue = {
647
645
pending : null ,
648
646
dispatch : null ,
647
+ pendingTransition : null ,
649
648
lastRenderedReducer : reducer ,
650
649
lastRenderedState : ( initialState : any ) ,
651
650
} ) ;
@@ -853,6 +852,7 @@ function mountState<S>(
853
852
const queue = ( hook . queue = {
854
853
pending : null ,
855
854
dispatch : null ,
855
+ pendingTransition : null ,
856
856
lastRenderedReducer : basicStateReducer ,
857
857
lastRenderedState : ( initialState : any ) ,
858
858
} ) ;
@@ -1208,89 +1208,14 @@ function rerenderDeferredValue<T>(
1208
1208
return prevValue ;
1209
1209
}
1210
1210
1211
- function startTransition ( fiber , instance , config , callback ) {
1212
- let resolvedConfig : SuspenseConfig | null =
1213
- config === undefined ? null : config ;
1214
-
1215
- // TODO: runWithPriority shouldn't be necessary here. React should manage its
1216
- // own concept of priority, and only consult Scheduler for updates that are
1217
- // scheduled from outside a React context.
1218
- const priorityLevel = getCurrentPriorityLevel ( ) ;
1219
- runWithPriority (
1220
- priorityLevel < UserBlockingPriority ? UserBlockingPriority : priorityLevel ,
1221
- ( ) => {
1222
- const currentTime = requestCurrentTimeForUpdate ( ) ;
1223
- const expirationTime = computeExpirationForFiber (
1224
- currentTime ,
1225
- fiber ,
1226
- null ,
1227
- ) ;
1228
- scheduleWork ( fiber , expirationTime ) ;
1229
- } ,
1230
- ) ;
1231
- runWithPriority (
1232
- priorityLevel > NormalPriority ? NormalPriority : priorityLevel ,
1233
- ( ) => {
1234
- const currentTime = requestCurrentTimeForUpdate ( ) ;
1235
- let expirationTime = computeExpirationForFiber (
1236
- currentTime ,
1237
- fiber ,
1238
- resolvedConfig ,
1239
- ) ;
1240
- // Set the expiration time at which the pending transition will finish.
1241
- // Because there's only a single transition per useTransition hook, we
1242
- // don't need a queue here; we can cheat by only tracking the most
1243
- // recently scheduled transition.
1244
- // TODO: This trick depends on transition expiration times being
1245
- // monotonically decreasing in priority, but since expiration times
1246
- // currently correspond to `timeoutMs`, that might not be true if
1247
- // `timeoutMs` changes to something smaller before the previous transition
1248
- // resolves. But this is a temporary edge case, since we're about to
1249
- // remove the correspondence between `timeoutMs` and the expiration time.
1250
- const oldPendingExpirationTime = instance . pendingExpirationTime ;
1251
- while (
1252
- oldPendingExpirationTime !== NoWork &&
1253
- oldPendingExpirationTime <= expirationTime
1254
- ) {
1255
- // Temporary hack to make pendingExpirationTime monotonically decreasing
1256
- if ( resolvedConfig === null ) {
1257
- resolvedConfig = {
1258
- timeoutMs : 5250 ,
1259
- } ;
1260
- } else {
1261
- resolvedConfig = {
1262
- timeoutMs : ( resolvedConfig . timeoutMs | 0 || 5000 ) + 250 ,
1263
- busyDelayMs : resolvedConfig . busyDelayMs ,
1264
- busyMinDurationMs : resolvedConfig . busyMinDurationMs ,
1265
- } ;
1266
- }
1267
- expirationTime = computeExpirationForFiber (
1268
- currentTime ,
1269
- fiber ,
1270
- resolvedConfig ,
1271
- ) ;
1272
- }
1273
- instance . pendingExpirationTime = expirationTime ;
1274
-
1275
- scheduleWork ( fiber , expirationTime ) ;
1276
- const previousConfig = ReactCurrentBatchConfig . suspense ;
1277
- ReactCurrentBatchConfig . suspense = resolvedConfig ;
1278
- try {
1279
- callback ( ) ;
1280
- } finally {
1281
- ReactCurrentBatchConfig . suspense = previousConfig ;
1282
- }
1283
- } ,
1284
- ) ;
1285
- }
1286
-
1287
1211
function mountTransition (
1288
1212
config : SuspenseConfig | void | null ,
1289
1213
) : [ ( ( ) => void ) => void , boolean ] {
1290
1214
const hook = mountWorkInProgressHook ( ) ;
1291
-
1215
+ const fiber = ( ( currentlyRenderingFiber : any ) : Fiber ) ;
1292
1216
const instance : TransitionInstance = {
1293
1217
pendingExpirationTime : NoWork ,
1218
+ fiber ,
1294
1219
} ;
1295
1220
// TODO: Intentionally storing this on the queue field to avoid adding a new/
1296
1221
// one; `queue` should be a union.
@@ -1302,15 +1227,9 @@ function mountTransition(
1302
1227
// Then we don't have to recompute the callback whenever it changes. However,
1303
1228
// if we don't end up changing the API, we should at least optimize this
1304
1229
// to use the same hook instead of a separate hook just for the callback.
1305
- const start = mountCallback (
1306
- startTransition . bind (
1307
- null ,
1308
- ( ( currentlyRenderingFiber : any ) : Fiber ) ,
1309
- instance ,
1310
- config ,
1311
- ) ,
1312
- [ config ] ,
1313
- ) ;
1230
+ const start = mountCallback ( startTransition . bind ( null , instance , config ) , [
1231
+ config ,
1232
+ ] ) ;
1314
1233
1315
1234
const resolvedExpirationTime = NoWork ;
1316
1235
hook . memoizedState = {
@@ -1406,15 +1325,9 @@ function updateTransition(
1406
1325
resolvedExpirationTime : newResolvedExpirationTime ,
1407
1326
} ;
1408
1327
1409
- const start = updateCallback (
1410
- startTransition . bind (
1411
- null ,
1412
- ( ( currentlyRenderingFiber : any ) : Fiber ) ,
1413
- instance ,
1414
- config ,
1415
- ) ,
1416
- [ config ] ,
1417
- ) ;
1328
+ const start = updateCallback ( startTransition . bind ( null , instance , config ) , [
1329
+ config ,
1330
+ ] ) ;
1418
1331
1419
1332
return [ start , newIsPending ] ;
1420
1333
}
@@ -1436,6 +1349,7 @@ function dispatchAction<S, A>(
1436
1349
1437
1350
const currentTime = requestCurrentTimeForUpdate ( ) ;
1438
1351
const suspenseConfig = requestCurrentSuspenseConfig ( ) ;
1352
+ const transition = requestCurrentTransition ( ) ;
1439
1353
const expirationTime = computeExpirationForFiber (
1440
1354
currentTime ,
1441
1355
fiber ,
@@ -1466,6 +1380,19 @@ function dispatchAction<S, A>(
1466
1380
}
1467
1381
queue . pending = update ;
1468
1382
1383
+ if ( transition !== null ) {
1384
+ const prevPendingTransition = queue . pendingTransition ;
1385
+ if ( transition !== prevPendingTransition ) {
1386
+ queue . pendingTransition = transition ;
1387
+ if ( prevPendingTransition !== null ) {
1388
+ // There's already a pending transition on this queue. The new
1389
+ // transition supersedes the old one. Turn of the `isPending` state
1390
+ // of the previous transition.
1391
+ cancelPendingTransition ( prevPendingTransition ) ;
1392
+ }
1393
+ }
1394
+ }
1395
+
1469
1396
const alternate = fiber . alternate ;
1470
1397
if (
1471
1398
fiber === currentlyRenderingFiber ||
@@ -1524,6 +1451,7 @@ function dispatchAction<S, A>(
1524
1451
warnIfNotCurrentlyActingUpdatesInDev ( fiber ) ;
1525
1452
}
1526
1453
}
1454
+
1527
1455
scheduleWork ( fiber , expirationTime ) ;
1528
1456
}
1529
1457
}
0 commit comments