Clean up enableUnifiedSyncLane flag (#30062)

`enableUnifiedSyncLane` now passes everywhere. Let's clean it up

Implemented with https://github.com/facebook/react/pull/27646

Flag enabled with https://github.com/facebook/react/pull/27646,
https://github.com/facebook/react/pull/28269,
https://github.com/facebook/react/pull/29052
This commit is contained in:
Jack Pope
2024-06-24 11:18:22 -04:00
committed by GitHub
parent 7608516479
commit c21bcd627b
20 changed files with 62 additions and 276 deletions

View File

@@ -313,21 +313,12 @@ describe('ReactDOMFiberAsync', () => {
assertLog([]);
});
// Only the active updates have flushed
if (gate(flags => flags.enableUnifiedSyncLane)) {
expect(container.textContent).toEqual('ABC');
assertLog(['ABC']);
} else {
expect(container.textContent).toEqual('BC');
assertLog(['BC']);
}
expect(container.textContent).toEqual('ABC');
assertLog(['ABC']);
await act(() => {
instance.push('D');
if (gate(flags => flags.enableUnifiedSyncLane)) {
expect(container.textContent).toEqual('ABC');
} else {
expect(container.textContent).toEqual('BC');
}
expect(container.textContent).toEqual('ABC');
assertLog([]);
});
assertLog(['ABCD']);

View File

@@ -23,7 +23,6 @@ import {
enableRetryLaneExpiration,
enableSchedulingProfiler,
enableTransitionTracing,
enableUnifiedSyncLane,
enableUpdaterTracking,
syncLaneExpirationMs,
transitionLaneExpirationMs,
@@ -51,9 +50,8 @@ export const InputContinuousLane: Lane = /* */ 0b0000000000000000000
export const DefaultHydrationLane: Lane = /* */ 0b0000000000000000000000000010000;
export const DefaultLane: Lane = /* */ 0b0000000000000000000000000100000;
export const SyncUpdateLanes: Lane = enableUnifiedSyncLane
? SyncLane | InputContinuousLane | DefaultLane
: SyncLane;
export const SyncUpdateLanes: Lane =
SyncLane | InputContinuousLane | DefaultLane;
const TransitionHydrationLane: Lane = /* */ 0b0000000000000000000000001000000;
const TransitionLanes: Lanes = /* */ 0b0000000001111111111111110000000;
@@ -151,11 +149,9 @@ let nextTransitionLane: Lane = TransitionLane1;
let nextRetryLane: Lane = RetryLane1;
function getHighestPriorityLanes(lanes: Lanes | Lane): Lanes {
if (enableUnifiedSyncLane) {
const pendingSyncLanes = lanes & SyncUpdateLanes;
if (pendingSyncLanes !== 0) {
return pendingSyncLanes;
}
const pendingSyncLanes = lanes & SyncUpdateLanes;
if (pendingSyncLanes !== 0) {
return pendingSyncLanes;
}
switch (getHighestPriorityLane(lanes)) {
case SyncHydrationLane:
@@ -826,7 +822,7 @@ export function getBumpedLaneForHydration(
const renderLane = getHighestPriorityLane(renderLanes);
let lane;
if (enableUnifiedSyncLane && (renderLane & SyncUpdateLanes) !== NoLane) {
if ((renderLane & SyncUpdateLanes) !== NoLane) {
lane = SyncHydrationLane;
} else {
switch (renderLane) {

View File

@@ -698,15 +698,10 @@ describe('Activity', () => {
);
// Before the inner update can finish, we receive another pair of updates.
if (gate(flags => flags.enableUnifiedSyncLane)) {
React.startTransition(() => {
setOuter(2);
setInner(2);
});
} else {
React.startTransition(() => {
setOuter(2);
setInner(2);
}
});
// Also, before either of these new updates are processed, the hidden
// tree is revealed at high priority.

View File

@@ -159,17 +159,7 @@ describe('ReactBlockingMode', () => {
);
// Now flush the first update
if (gate(flags => flags.enableUnifiedSyncLane)) {
assertLog(['A1', 'B1']);
expect(root).toMatchRenderedOutput('A1B1');
} else {
// Only the second update should have flushed synchronously
assertLog(['B1']);
expect(root).toMatchRenderedOutput('A0B1');
// Now flush the first update
await waitForAll(['A1']);
expect(root).toMatchRenderedOutput('A1B1');
}
assertLog(['A1', 'B1']);
expect(root).toMatchRenderedOutput('A1B1');
});
});

View File

@@ -39,13 +39,9 @@ describe('ReactClassSetStateCallback', () => {
assertLog([0]);
await act(() => {
if (gate(flags => flags.enableUnifiedSyncLane)) {
React.startTransition(() => {
app.setState({step: 1}, () => Scheduler.log('Callback 1'));
});
} else {
React.startTransition(() => {
app.setState({step: 1}, () => Scheduler.log('Callback 1'));
}
});
ReactNoop.flushSync(() => {
app.setState({step: 2}, () => Scheduler.log('Callback 2'));
});

View File

@@ -102,20 +102,13 @@ describe('ReactFlushSync', () => {
// The passive effect will schedule a sync update and a normal update.
// They should commit in two separate batches. First the sync one.
await waitForPaint(
gate(flags => flags.enableUnifiedSyncLane) ? ['1, 1'] : ['1, 0'],
);
await waitForPaint(['1, 1']);
// The remaining update is not sync
ReactDOM.flushSync();
assertLog([]);
if (gate(flags => flags.enableUnifiedSyncLane)) {
await waitForPaint([]);
} else {
// Now flush it.
await waitForPaint(['1, 1']);
}
await waitForPaint([]);
});
expect(getVisibleChildren(container)).toEqual('1, 1');

View File

@@ -541,13 +541,8 @@ describe('ReactHooks', () => {
});
};
if (gate(flags => flags.enableUnifiedSyncLane)) {
// Update at transition priority
React.startTransition(() => update(n => n * 100));
} else {
// Update at normal priority
ReactTestRenderer.unstable_batchedUpdates(() => update(n => n * 100));
}
// Update at transition priority
React.startTransition(() => update(n => n * 100));
// The new state is eagerly computed.
assertLog(['Compute state (1 -> 100)']);

View File

@@ -899,15 +899,8 @@ describe('ReactHooksWithNoopRenderer', () => {
ReactNoop.flushSync(() => {
counter.current.dispatch(INCREMENT);
});
if (gate(flags => flags.enableUnifiedSyncLane)) {
assertLog(['Count: 4']);
expect(ReactNoop).toMatchRenderedOutput(<span prop="Count: 4" />);
} else {
assertLog(['Count: 1']);
expect(ReactNoop).toMatchRenderedOutput(<span prop="Count: 1" />);
await waitForAll(['Count: 4']);
expect(ReactNoop).toMatchRenderedOutput(<span prop="Count: 4" />);
}
assertLog(['Count: 4']);
expect(ReactNoop).toMatchRenderedOutput(<span prop="Count: 4" />);
});
});
@@ -1613,11 +1606,7 @@ describe('ReactHooksWithNoopRenderer', () => {
// As a result we, somewhat surprisingly, commit them in the opposite order.
// This should be fine because any non-discrete set of work doesn't guarantee order
// and easily could've happened slightly later too.
if (gate(flags => flags.enableUnifiedSyncLane)) {
assertLog(['Will set count to 1', 'Count: 1']);
} else {
assertLog(['Will set count to 1', 'Count: 2', 'Count: 1']);
}
assertLog(['Will set count to 1', 'Count: 1']);
expect(ReactNoop).toMatchRenderedOutput(<span prop="Count: 1" />);
});

View File

@@ -156,23 +156,11 @@ describe('ReactIncrementalUpdates', () => {
}
// Schedule some async updates
if (
gate(
flags =>
!flags.forceConcurrentByDefaultForTesting ||
flags.enableUnifiedSyncLane,
)
) {
React.startTransition(() => {
instance.setState(createUpdate('a'));
instance.setState(createUpdate('b'));
instance.setState(createUpdate('c'));
});
} else {
React.startTransition(() => {
instance.setState(createUpdate('a'));
instance.setState(createUpdate('b'));
instance.setState(createUpdate('c'));
}
});
// Begin the updates but don't flush them yet
await waitFor(['a', 'b', 'c']);
@@ -189,58 +177,22 @@ describe('ReactIncrementalUpdates', () => {
});
// The sync updates should have flushed, but not the async ones.
if (
gate(
flags =>
!flags.forceConcurrentByDefaultForTesting &&
flags.enableUnifiedSyncLane,
)
) {
assertLog(['d', 'e', 'f']);
expect(ReactNoop).toMatchRenderedOutput(<span prop="def" />);
} else {
// Update d was dropped and replaced by e.
assertLog(['e', 'f']);
expect(ReactNoop).toMatchRenderedOutput(<span prop="ef" />);
}
assertLog(['d', 'e', 'f']);
expect(ReactNoop).toMatchRenderedOutput(<span prop="def" />);
// Now flush the remaining work. Even though e and f were already processed,
// they should be processed again, to ensure that the terminal state
// is deterministic.
if (
gate(
flags =>
!flags.forceConcurrentByDefaultForTesting &&
!flags.enableUnifiedSyncLane,
)
) {
await waitForAll([
// Since 'g' is in a transition, we'll process 'd' separately first.
// That causes us to process 'd' with 'e' and 'f' rebased.
'd',
'e',
'f',
// Then we'll re-process everything for 'g'.
'a',
'b',
'c',
'd',
'e',
'f',
'g',
]);
} else {
await waitForAll([
// Then we'll re-process everything for 'g'.
'a',
'b',
'c',
'd',
'e',
'f',
'g',
]);
}
await waitForAll([
// Then we'll re-process everything for 'g'.
'a',
'b',
'c',
'd',
'e',
'f',
'g',
]);
expect(ReactNoop).toMatchRenderedOutput(<span prop="abcdefg" />);
});
@@ -267,23 +219,11 @@ describe('ReactIncrementalUpdates', () => {
}
// Schedule some async updates
if (
gate(
flags =>
!flags.forceConcurrentByDefaultForTesting ||
flags.enableUnifiedSyncLane,
)
) {
React.startTransition(() => {
instance.setState(createUpdate('a'));
instance.setState(createUpdate('b'));
instance.setState(createUpdate('c'));
});
} else {
React.startTransition(() => {
instance.setState(createUpdate('a'));
instance.setState(createUpdate('b'));
instance.setState(createUpdate('c'));
}
});
// Begin the updates but don't flush them yet
await waitFor(['a', 'b', 'c']);
@@ -303,57 +243,22 @@ describe('ReactIncrementalUpdates', () => {
});
// The sync updates should have flushed, but not the async ones.
if (
gate(
flags =>
!flags.forceConcurrentByDefaultForTesting &&
flags.enableUnifiedSyncLane,
)
) {
assertLog(['d', 'e', 'f']);
} else {
// Update d was dropped and replaced by e.
assertLog(['e', 'f']);
}
assertLog(['d', 'e', 'f']);
expect(ReactNoop).toMatchRenderedOutput(<span prop="f" />);
// Now flush the remaining work. Even though e and f were already processed,
// they should be processed again, to ensure that the terminal state
// is deterministic.
if (
gate(
flags =>
!flags.forceConcurrentByDefaultForTesting &&
!flags.enableUnifiedSyncLane,
)
) {
await waitForAll([
// Since 'g' is in a transition, we'll process 'd' separately first.
// That causes us to process 'd' with 'e' and 'f' rebased.
'd',
'e',
'f',
// Then we'll re-process everything for 'g'.
'a',
'b',
'c',
'd',
'e',
'f',
'g',
]);
} else {
await waitForAll([
// Then we'll re-process everything for 'g'.
'a',
'b',
'c',
'd',
'e',
'f',
'g',
]);
}
await waitForAll([
// Then we'll re-process everything for 'g'.
'a',
'b',
'c',
'd',
'e',
'f',
'g',
]);
expect(ReactNoop).toMatchRenderedOutput(<span prop="fg" />);
});
@@ -684,25 +589,7 @@ describe('ReactIncrementalUpdates', () => {
pushToLog('B'),
);
});
if (gate(flags => flags.enableUnifiedSyncLane)) {
assertLog(['Committed: B', 'Committed: BCD', 'Committed: ABCD']);
} else {
assertLog([
// A and B are pending. B is higher priority, so we'll render that first.
'Committed: B',
// Because A comes first in the queue, we're now in rebase mode. B must
// be rebased on top of A. Also, in a layout effect, we received two new
// updates: C and D. C is user-blocking and D is synchronous.
//
// First render the synchronous update. What we're testing here is that
// B *is not dropped* even though it has lower than sync priority. That's
// because we already committed it. However, this render should not
// include C, because that update wasn't already committed.
'Committed: BD',
'Committed: BCD',
'Committed: ABCD',
]);
}
assertLog(['Committed: B', 'Committed: BCD', 'Committed: ABCD']);
expect(root).toMatchRenderedOutput('ABCD');
});
@@ -744,25 +631,7 @@ describe('ReactIncrementalUpdates', () => {
pushToLog('B'),
);
});
if (gate(flags => flags.enableUnifiedSyncLane)) {
assertLog(['Committed: B', 'Committed: BCD', 'Committed: ABCD']);
} else {
assertLog([
// A and B are pending. B is higher priority, so we'll render that first.
'Committed: B',
// Because A comes first in the queue, we're now in rebase mode. B must
// be rebased on top of A. Also, in a layout effect, we received two new
// updates: C and D. C is user-blocking and D is synchronous.
//
// First render the synchronous update. What we're testing here is that
// B *is not dropped* even though it has lower than sync priority. That's
// because we already committed it. However, this render should not
// include C, because that update wasn't already committed.
'Committed: BD',
'Committed: BCD',
'Committed: ABCD',
]);
}
assertLog(['Committed: B', 'Committed: BCD', 'Committed: ABCD']);
expect(root).toMatchRenderedOutput('ABCD');
});

View File

@@ -3506,7 +3506,6 @@ describe('ReactSuspenseWithNoopRenderer', () => {
});
// @gate enableLegacyCache
// @gate forceConcurrentByDefaultForTesting
it('regression: ping at high priority causes update to be dropped', async () => {
const {useState, useTransition} = React;
@@ -3573,10 +3572,9 @@ describe('ReactSuspenseWithNoopRenderer', () => {
});
await waitFor([
'B',
'Suspend! [A1]',
'Loading...',
'B',
'Suspend! [A2]',
'Loading...',
'Suspend! [B2]',

View File

@@ -925,28 +925,15 @@ describe('ReactTransition', () => {
updateNormalPri();
});
if (gate(flags => flags.enableUnifiedSyncLane)) {
assertLog([
'Normal pri: 0',
'Commit',
assertLog([
'Normal pri: 0',
'Commit',
// Normal pri update.
'Transition pri: 1',
'Normal pri: 1',
'Commit',
]);
} else {
assertLog([
// Finish transition update.
'Normal pri: 0',
'Commit',
// Normal pri update.
'Transition pri: 1',
'Normal pri: 1',
'Commit',
]);
}
// Normal pri update.
'Transition pri: 1',
'Normal pri: 1',
'Commit',
]);
expect(root).toMatchRenderedOutput('Transition pri: 1, Normal pri: 1');
});

View File

@@ -210,8 +210,6 @@ export const enableUseDeferredValueInitialArg = true;
// Enables time slicing for updates that aren't wrapped in startTransition.
export const forceConcurrentByDefaultForTesting = false;
export const enableUnifiedSyncLane = true;
// Adds an opt-in to time slicing for updates that aren't wrapped in startTransition.
export const allowConcurrentByDefault = false;

View File

@@ -79,7 +79,6 @@ export const enableSuspenseCallback = false;
export const enableTaint = true;
export const enableTransitionTracing = false;
export const enableTrustedTypesIntegration = false;
export const enableUnifiedSyncLane = true;
export const enableUpdaterTracking = __PROFILE__;
export const enableUseDeferredValueInitialArg = true;
export const enableUseEffectEventHook = false;

View File

@@ -71,7 +71,6 @@ export const enableSuspenseCallback = false;
export const enableTaint = true;
export const enableTransitionTracing = false;
export const enableTrustedTypesIntegration = false;
export const enableUnifiedSyncLane = true;
export const enableUseDeferredValueInitialArg = true;
export const enableUseEffectEventHook = false;
export const enableUseMemoCacheHook = true;

View File

@@ -54,7 +54,6 @@ export const disableSchedulerTimeoutInWorkLoop = false;
export const enableLazyContextPropagation = false;
export const enableLegacyHidden = false;
export const forceConcurrentByDefaultForTesting = false;
export const enableUnifiedSyncLane = __EXPERIMENTAL__;
export const allowConcurrentByDefault = false;
export const consoleManagedByDevToolsDuringStrictMode = false;

View File

@@ -66,7 +66,6 @@ export const enableSuspenseCallback = false;
export const enableTaint = true;
export const enableTransitionTracing = false;
export const enableTrustedTypesIntegration = false;
export const enableUnifiedSyncLane = true;
export const enableUpdaterTracking = false;
export const enableUseDeferredValueInitialArg = __EXPERIMENTAL__;
export const enableUseEffectEventHook = false;

View File

@@ -56,7 +56,6 @@ export const disableSchedulerTimeoutInWorkLoop = false;
export const enableLazyContextPropagation = false;
export const enableLegacyHidden = false;
export const forceConcurrentByDefaultForTesting = false;
export const enableUnifiedSyncLane = true;
export const allowConcurrentByDefault = true;
export const consoleManagedByDevToolsDuringStrictMode = false;

View File

@@ -16,7 +16,6 @@
export const disableSchedulerTimeoutInWorkLoop = __VARIANT__;
export const enableLazyContextPropagation = __VARIANT__;
export const forceConcurrentByDefaultForTesting = __VARIANT__;
export const enableUnifiedSyncLane = __VARIANT__;
export const enableTransitionTracing = __VARIANT__;
export const enableDeferRootSchedulingToMicrotask = __VARIANT__;
export const alwaysThrottleRetries = true;

View File

@@ -18,7 +18,6 @@ export const {
enableTrustedTypesIntegration,
enableDebugTracing,
enableLazyContextPropagation,
enableUnifiedSyncLane,
enableRetryLaneExpiration,
enableTransitionTracing,
enableDeferRootSchedulingToMicrotask,

View File

@@ -434,13 +434,9 @@ describe('useSubscription', () => {
observableA.next('a-2');
// Update again
if (gate(flags => flags.enableUnifiedSyncLane)) {
React.startTransition(() => {
root.render(<Parent observed={observableA} />);
});
} else {
React.startTransition(() => {
root.render(<Parent observed={observableA} />);
}
});
// Flush everything and ensure that the correct subscribable is used
await waitForAll([