Skip to content

Commit 381939d

Browse files
author
Brian Vaughn
committed
Refactor pending mutable source expiration time to be per root, not per root + per source
1 parent ab1fd91 commit 381939d

File tree

5 files changed

+14
-37
lines changed

5 files changed

+14
-37
lines changed

packages/react-reconciler/src/ReactFiberHooks.js

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -879,7 +879,7 @@ function useMutableSourceImpl<Source, Snapshot>(
879879
// Is it safe to read from this source during the current render?
880880
let isSafeToReadFromSource = false;
881881

882-
if (pendingExpirationTime !== null) {
882+
if (pendingExpirationTime !== NoWork) {
883883
// If the source has pending updates, we can use the current render's expiration
884884
// time to determine if it's safe to read again from the source.
885885
isSafeToReadFromSource =
@@ -958,12 +958,11 @@ function useMutableSourceImpl<Source, Snapshot>(
958958

959959
const create = () => {
960960
const scheduleUpdate = () => {
961-
const alreadyScheduledExpirationTime = root.mutableSourcePendingUpdateMap.get(
962-
source,
963-
);
961+
const alreadyScheduledExpirationTime =
962+
root.mutableSourcePendingUpdateTime;
964963

965964
// If an update is already scheduled for this source, re-use the same priority.
966-
if (alreadyScheduledExpirationTime !== undefined) {
965+
if (alreadyScheduledExpirationTime !== NoWork) {
967966
scheduleUpdateOnFiber(fiber, alreadyScheduledExpirationTime);
968967
} else {
969968
const currentTime = requestCurrentTimeForUpdate();
@@ -978,7 +977,7 @@ function useMutableSourceImpl<Source, Snapshot>(
978977
// Make sure reads during future renders will know there's a pending update.
979978
// This will prevent a higher priority update from reading a newer version of the source,
980979
// and causing a tear between that render and previous renders.
981-
root.mutableSourcePendingUpdateMap.set(source, expirationTime);
980+
root.mutableSourcePendingUpdateTime = expirationTime;
982981
}
983982
};
984983

packages/react-reconciler/src/ReactFiberRoot.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import type {Thenable} from './ReactFiberWorkLoop';
1515
import type {Interaction} from 'scheduler/src/Tracing';
1616
import type {SuspenseHydrationCallbacks} from './ReactFiberSuspenseComponent';
1717
import type {ReactPriorityLevel} from './SchedulerWithReactIntegration';
18-
import type {MutableSourcePendingUpdateMap} from 'shared/ReactTypes';
1918

2019
import {noTimeout} from './ReactFiberHostConfig';
2120
import {createHostRootFiber} from './ReactFiber';
@@ -78,7 +77,7 @@ type BaseFiberRootProperties = {|
7877
lastExpiredTime: ExpirationTime,
7978
// Used by useMutableSource hook to avoid tearing within this root
8079
// when external, mutable sources are read from during render.
81-
mutableSourcePendingUpdateMap: MutableSourcePendingUpdateMap,
80+
mutableSourcePendingUpdateTime: ExpirationTime,
8281
|};
8382

8483
// The following attributes are only used by interaction tracing builds.
@@ -128,7 +127,7 @@ function FiberRootNode(containerInfo, tag, hydrate) {
128127
this.nextKnownPendingLevel = NoWork;
129128
this.lastPingedTime = NoWork;
130129
this.lastExpiredTime = NoWork;
131-
this.mutableSourcePendingUpdateMap = new Map();
130+
this.mutableSourcePendingUpdateTime = NoWork;
132131

133132
if (enableSchedulerTracing) {
134133
this.interactionThreadID = unstable_getThreadID();

packages/react-reconciler/src/ReactMutableSource.js

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import type {FiberRoot} from 'react-reconciler/src/ReactFiberRoot';
1212
import type {MutableSource, MutableSourceVersion} from 'shared/ReactTypes';
1313

1414
import {isPrimaryRenderer} from './ReactFiberHostConfig';
15+
import {NoWork} from './ReactFiberExpirationTime';
1516

1617
// Work in progress version numbers only apply to a single render,
1718
// and should be reset before starting a new render.
@@ -23,14 +24,9 @@ export function clearPendingUpdates(
2324
root: FiberRoot,
2425
expirationTime: ExpirationTime,
2526
): void {
26-
// Remove pending mutable source entries that we've completed processing.
27-
root.mutableSourcePendingUpdateMap.forEach(
28-
(pendingExpirationTime, mutableSource) => {
29-
if (pendingExpirationTime <= expirationTime) {
30-
root.mutableSourcePendingUpdateMap.delete(mutableSource);
31-
}
32-
},
33-
);
27+
if (root.mutableSourcePendingUpdateTime <= expirationTime) {
28+
root.mutableSourcePendingUpdateTime = NoWork;
29+
}
3430
}
3531

3632
export function resetWorkInProgressVersions(): void {
@@ -52,9 +48,8 @@ export function resetWorkInProgressVersions(): void {
5248
export function getPendingExpirationTime(
5349
root: FiberRoot,
5450
source: MutableSource<any>,
55-
): ExpirationTime | null {
56-
const expirationTime = root.mutableSourcePendingUpdateMap.get(source);
57-
return expirationTime !== undefined ? expirationTime : null;
51+
): ExpirationTime {
52+
return root.mutableSourcePendingUpdateTime;
5853
}
5954

6055
export function getWorkInProgressVersion(

packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.internal.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2084,11 +2084,7 @@ describe('ReactHooksWithNoopRenderer', () => {
20842084
source.value = 'two';
20852085

20862086
// Render work should restart and the updated value should be used
2087-
expect(Scheduler).toFlushAndYieldThrough([
2088-
'a:two',
2089-
'b:two',
2090-
'Sync effect',
2091-
]);
2087+
expect(Scheduler).toFlushAndYield(['a:two', 'b:two', 'Sync effect']);
20922088
});
20932089

20942090
it('should schedule an update if a new source is mutated between render and commit (subscription)', () => {

packages/shared/ReactTypes.js

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
* @flow
88
*/
99

10-
import type {ExpirationTime} from 'react-reconciler/src/ReactFiberExpirationTime';
11-
1210
export type ReactNode =
1311
| React$Element<any>
1412
| ReactPortal
@@ -194,16 +192,6 @@ export type ReactScopeInstance = {|
194192
// so long as it changes every time any part of the source changes.
195193
export type MutableSourceVersion = $NonMaybeType<mixed>;
196194

197-
// Tracks expiration time for all mutable sources with pending updates.
198-
// Used to determine if a source is safe to read during updates.
199-
// If there are no entries in this map for a given source,
200-
// or if the current render’s expiration time is ≤ this value,
201-
// it is safe to read from the source without tearing.
202-
export type MutableSourcePendingUpdateMap = Map<
203-
MutableSource<any>,
204-
ExpirationTime,
205-
>;
206-
207195
export type MutableSource<Source: $NonMaybeType<mixed>> = {|
208196
_source: Source,
209197

0 commit comments

Comments
 (0)