Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace unbatchedUpdates with flushSync #21776

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Object {
6 => 1,
},
"passiveEffectDuration": null,
"priorityLevel": "Normal",
"priorityLevel": "Immediate",
"timestamp": 16,
"updaters": Array [
Object {
Expand Down Expand Up @@ -87,7 +87,7 @@ Object {
4 => 2,
},
"passiveEffectDuration": null,
"priorityLevel": "Normal",
"priorityLevel": "Immediate",
"timestamp": 15,
"updaters": Array [
Object {
Expand Down Expand Up @@ -186,7 +186,7 @@ Object {
6 => 1,
},
"passiveEffectDuration": null,
"priorityLevel": "Normal",
"priorityLevel": "Immediate",
"timestamp": 12,
"updaters": Array [
Object {
Expand Down Expand Up @@ -445,7 +445,7 @@ Object {
],
],
"passiveEffectDuration": null,
"priorityLevel": "Normal",
"priorityLevel": "Immediate",
"timestamp": 12,
"updaters": Array [
Object {
Expand Down Expand Up @@ -938,7 +938,7 @@ Object {
],
],
"passiveEffectDuration": null,
"priorityLevel": "Normal",
"priorityLevel": "Immediate",
"timestamp": 11,
"updaters": Array [
Object {
Expand Down Expand Up @@ -1597,7 +1597,7 @@ Object {
17 => 1,
},
"passiveEffectDuration": null,
"priorityLevel": "Normal",
"priorityLevel": "Immediate",
"timestamp": 24,
"updaters": Array [
Object {
Expand Down Expand Up @@ -1687,7 +1687,7 @@ Object {
"fiberActualDurations": Map {},
"fiberSelfDurations": Map {},
"passiveEffectDuration": 0,
"priorityLevel": "Normal",
"priorityLevel": "Immediate",
"timestamp": 34,
"updaters": Array [
Object {
Expand Down Expand Up @@ -2223,7 +2223,7 @@ Object {
],
],
"passiveEffectDuration": null,
"priorityLevel": "Normal",
"priorityLevel": "Immediate",
"timestamp": 24,
"updaters": Array [
Object {
Expand Down Expand Up @@ -2310,7 +2310,7 @@ Object {
"fiberActualDurations": Array [],
"fiberSelfDurations": Array [],
"passiveEffectDuration": 0,
"priorityLevel": "Normal",
"priorityLevel": "Immediate",
"timestamp": 34,
"updaters": Array [
Object {
Expand Down Expand Up @@ -2431,7 +2431,7 @@ Object {
2 => 0,
},
"passiveEffectDuration": null,
"priorityLevel": "Normal",
"priorityLevel": "Immediate",
"timestamp": 0,
"updaters": Array [
Object {
Expand Down Expand Up @@ -2506,7 +2506,7 @@ Object {
3 => 0,
},
"passiveEffectDuration": 0,
"priorityLevel": "Normal",
"priorityLevel": "Immediate",
"timestamp": 0,
"updaters": Array [
Object {
Expand Down Expand Up @@ -2715,7 +2715,7 @@ Object {
],
],
"passiveEffectDuration": 0,
"priorityLevel": "Normal",
"priorityLevel": "Immediate",
"timestamp": 0,
"updaters": Array [
Object {
Expand Down Expand Up @@ -3071,7 +3071,7 @@ Object {
7 => 0,
},
"passiveEffectDuration": null,
"priorityLevel": "Normal",
"priorityLevel": "Immediate",
"timestamp": 0,
"updaters": Array [
Object {
Expand Down Expand Up @@ -3515,7 +3515,7 @@ Object {
],
],
"passiveEffectDuration": null,
"priorityLevel": "Normal",
"priorityLevel": "Immediate",
"timestamp": 0,
"updaters": Array [
Object {
Expand Down
12 changes: 6 additions & 6 deletions packages/react-dom/src/__tests__/ReactMount-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ describe('ReactMount', () => {
expect(calls).toBe(5);
});

it('initial mount is sync inside batchedUpdates, but task work is deferred until the end of the batch', () => {
it('initial mount of legacy root is sync inside batchedUpdates, as if it were wrapped in flushSync', () => {
const container1 = document.createElement('div');
const container2 = document.createElement('div');

Expand All @@ -302,12 +302,12 @@ describe('ReactMount', () => {

// Initial mount on another root. Should flush immediately.
ReactDOM.render(<Foo>a</Foo>, container2);
// The update did not flush yet.
expect(container1.textContent).toEqual('1');
// The initial mount flushed, but not the update scheduled in cDM.
expect(container2.textContent).toEqual('a');
// The earlier update also flushed, since flushSync flushes all pending
// sync work across all roots.
expect(container1.textContent).toEqual('2');
// Layout updates are also flushed synchronously
expect(container2.textContent).toEqual('a!');
});
// All updates have flushed.
expect(container1.textContent).toEqual('2');
expect(container2.textContent).toEqual('a!');
});
Expand Down
6 changes: 3 additions & 3 deletions packages/react-dom/src/client/ReactDOMLegacy.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
createContainer,
findHostInstanceWithNoPortals,
updateContainer,
unbatchedUpdates,
flushSyncWithoutWarningIfAlreadyRendering,
getPublicRootInstance,
findHostInstance,
findHostInstanceWithWarning,
Expand Down Expand Up @@ -174,7 +174,7 @@ function legacyRenderSubtreeIntoContainer(
};
}
// Initial mount should not be batched.
unbatchedUpdates(() => {
flushSyncWithoutWarningIfAlreadyRendering(() => {
updateContainer(children, fiberRoot, parentComponent, callback);
});
} else {
Expand Down Expand Up @@ -357,7 +357,7 @@ export function unmountComponentAtNode(container: Container) {
}

// Unmount should not be batched.
unbatchedUpdates(() => {
flushSyncWithoutWarningIfAlreadyRendering(() => {
legacyRenderSubtreeIntoContainer(null, null, container, false, () => {
// $FlowFixMe This should probably use `delete container._reactRootContainer`
container._reactRootContainer = null;
Expand Down
1 change: 0 additions & 1 deletion packages/react-noop-renderer/src/ReactNoop.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ export const {
flushExpired,
batchedUpdates,
deferredUpdates,
unbatchedUpdates,
discreteUpdates,
idleUpdates,
flushSync,
Expand Down
1 change: 0 additions & 1 deletion packages/react-noop-renderer/src/ReactNoopPersistent.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ export const {
flushExpired,
batchedUpdates,
deferredUpdates,
unbatchedUpdates,
discreteUpdates,
idleUpdates,
flushDiscreteUpdates,
Expand Down
2 changes: 0 additions & 2 deletions packages/react-noop-renderer/src/createReactNoop.js
Original file line number Diff line number Diff line change
Expand Up @@ -901,8 +901,6 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {

deferredUpdates: NoopRenderer.deferredUpdates,

unbatchedUpdates: NoopRenderer.unbatchedUpdates,

discreteUpdates: NoopRenderer.discreteUpdates,

idleUpdates<T>(fn: () => T): T {
Expand Down
5 changes: 0 additions & 5 deletions packages/react-reconciler/src/ReactFiberReconciler.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import {
createContainer as createContainer_old,
updateContainer as updateContainer_old,
batchedUpdates as batchedUpdates_old,
unbatchedUpdates as unbatchedUpdates_old,
deferredUpdates as deferredUpdates_old,
discreteUpdates as discreteUpdates_old,
flushControlled as flushControlled_old,
Expand Down Expand Up @@ -56,7 +55,6 @@ import {
createContainer as createContainer_new,
updateContainer as updateContainer_new,
batchedUpdates as batchedUpdates_new,
unbatchedUpdates as unbatchedUpdates_new,
deferredUpdates as deferredUpdates_new,
discreteUpdates as discreteUpdates_new,
flushControlled as flushControlled_new,
Expand Down Expand Up @@ -99,9 +97,6 @@ export const updateContainer = enableNewReconciler
export const batchedUpdates = enableNewReconciler
? batchedUpdates_new
: batchedUpdates_old;
export const unbatchedUpdates = enableNewReconciler
? unbatchedUpdates_new
: unbatchedUpdates_old;
export const deferredUpdates = enableNewReconciler
? deferredUpdates_new
: deferredUpdates_old;
Expand Down
2 changes: 0 additions & 2 deletions packages/react-reconciler/src/ReactFiberReconciler.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ import {
scheduleUpdateOnFiber,
flushRoot,
batchedUpdates,
unbatchedUpdates,
flushSync,
flushControlled,
deferredUpdates,
Expand Down Expand Up @@ -327,7 +326,6 @@ export function updateContainer(

export {
batchedUpdates,
unbatchedUpdates,
deferredUpdates,
discreteUpdates,
flushControlled,
Expand Down
2 changes: 0 additions & 2 deletions packages/react-reconciler/src/ReactFiberReconciler.old.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ import {
scheduleUpdateOnFiber,
flushRoot,
batchedUpdates,
unbatchedUpdates,
flushSync,
flushControlled,
deferredUpdates,
Expand Down Expand Up @@ -327,7 +326,6 @@ export function updateContainer(

export {
batchedUpdates,
unbatchedUpdates,
deferredUpdates,
discreteUpdates,
flushControlled,
Expand Down
90 changes: 18 additions & 72 deletions packages/react-reconciler/src/ReactFiberWorkLoop.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -246,12 +246,11 @@ const {

type ExecutionContext = number;

export const NoContext = /* */ 0b00000;
const BatchedContext = /* */ 0b00001;
const LegacyUnbatchedContext = /* */ 0b00010;
const RenderContext = /* */ 0b00100;
const CommitContext = /* */ 0b01000;
export const RetryAfterError = /* */ 0b10000;
export const NoContext = /* */ 0b0000;
const BatchedContext = /* */ 0b0001;
const RenderContext = /* */ 0b0010;
const CommitContext = /* */ 0b0100;
export const RetryAfterError = /* */ 0b1000;

type RootExitStatus = 0 | 1 | 2 | 3 | 4 | 5;
const RootIncomplete = 0;
Expand Down Expand Up @@ -515,35 +514,19 @@ export function scheduleUpdateOnFiber(
}
}

if (lane === SyncLane) {
if (
// Check if we're inside unbatchedUpdates
(executionContext & LegacyUnbatchedContext) !== NoContext &&
// Check if we're not already rendering
(executionContext & (RenderContext | CommitContext)) === NoContext
) {
// This is a legacy edge case. The initial mount of a ReactDOM.render-ed
// root inside of batchedUpdates should be synchronous, but layout updates
// should be deferred until the end of the batch.
performSyncWorkOnRoot(root);
} else {
ensureRootIsScheduled(root, eventTime);
if (
executionContext === NoContext &&
(fiber.mode & ConcurrentMode) === NoMode
) {
// Flush the synchronous work now, unless we're already working or inside
// a batch. This is intentionally inside scheduleUpdateOnFiber instead of
// scheduleCallbackForFiber to preserve the ability to schedule a callback
// without immediately flushing it. We only do this for user-initiated
// updates, to preserve historical behavior of legacy mode.
resetRenderTimer();
flushSyncCallbacksOnlyInLegacyMode();
}
}
} else {
// Schedule other updates after in case the callback is sync.
ensureRootIsScheduled(root, eventTime);
ensureRootIsScheduled(root, eventTime);
if (
lane === SyncLane &&
executionContext === NoContext &&
(fiber.mode & ConcurrentMode) === NoMode
) {
// Flush the synchronous work now, unless we're already working or inside
// a batch. This is intentionally inside scheduleUpdateOnFiber instead of
// scheduleCallbackForFiber to preserve the ability to schedule a callback
// without immediately flushing it. We only do this for user-initiated
// updates, to preserve historical behavior of legacy mode.
resetRenderTimer();
flushSyncCallbacksOnlyInLegacyMode();
}

return root;
Expand Down Expand Up @@ -1095,25 +1078,6 @@ export function discreteUpdates<A, B, C, D, R>(
}
}

export function unbatchedUpdates<A, R>(fn: (a: A) => R, a: A): R {
const prevExecutionContext = executionContext;
executionContext &= ~BatchedContext;
executionContext |= LegacyUnbatchedContext;
try {
return fn(a);
} finally {
executionContext = prevExecutionContext;
// If there were legacy sync updates, flush them at the end of the outer
// most batchedUpdates-like method.
if (executionContext === NoContext) {
resetRenderTimer();
// TODO: I think this call is redundant, because we flush inside
// scheduleUpdateOnFiber when LegacyUnbatchedContext is set.
flushSyncCallbacksOnlyInLegacyMode();
}
}
}

export function flushSyncWithoutWarningIfAlreadyRendering<A, R>(
fn: A => R,
a: A,
Expand Down Expand Up @@ -1954,24 +1918,6 @@ function commitRootImpl(root, renderPriorityLevel) {
throw error;
}

if ((executionContext & LegacyUnbatchedContext) !== NoContext) {
if (__DEV__) {
if (enableDebugTracing) {
logCommitStopped();
}
}

if (enableSchedulingProfiler) {
markCommitStopped();
}

// This is a legacy edge case. We just committed the initial mount of
// a ReactDOM.render-ed root inside of batchedUpdates. The commit fired
// synchronously, but layout updates should be deferred until the end
// of the batch.
return null;
}

// If the passive effects are the result of a discrete render, flush them
// synchronously at the end of the current task so that the result is
// immediately observable. Otherwise, we assume that they are not
Expand Down
Loading