diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.new.js b/packages/react-reconciler/src/ReactFiberWorkLoop.new.js
index 7c659b7775a1e..68a811e3fe088 100644
--- a/packages/react-reconciler/src/ReactFiberWorkLoop.new.js
+++ b/packages/react-reconciler/src/ReactFiberWorkLoop.new.js
@@ -1142,6 +1142,16 @@ export function unbatchedUpdates(fn: (a: A) => R, a: A): R {
export function flushSync(fn: A => R, a: A): R {
const prevExecutionContext = executionContext;
+ if ((prevExecutionContext & (RenderContext | CommitContext)) !== NoContext) {
+ if (__DEV__) {
+ console.error(
+ 'flushSync was called from inside a lifecycle method. React cannot ' +
+ 'flush when React is already rendering. Consider moving this call to ' +
+ 'a scheduler task or micro task.',
+ );
+ }
+ return fn(a);
+ }
executionContext |= BatchedContext;
const previousPriority = getCurrentUpdatePriority();
@@ -1158,17 +1168,7 @@ export function flushSync(fn: A => R, a: A): R {
// Flush the immediate callbacks that were scheduled during this batch.
// Note that this will happen even if batchedUpdates is higher up
// the stack.
- if ((executionContext & (RenderContext | CommitContext)) === NoContext) {
- flushSyncCallbacks();
- } else {
- if (__DEV__) {
- console.error(
- 'flushSync was called from inside a lifecycle method. React cannot ' +
- 'flush when React is already rendering. Consider moving this call to ' +
- 'a scheduler task or micro task.',
- );
- }
- }
+ flushSyncCallbacks();
}
}
diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.old.js b/packages/react-reconciler/src/ReactFiberWorkLoop.old.js
index 530646f8a4d29..729e8e6717d05 100644
--- a/packages/react-reconciler/src/ReactFiberWorkLoop.old.js
+++ b/packages/react-reconciler/src/ReactFiberWorkLoop.old.js
@@ -1142,6 +1142,16 @@ export function unbatchedUpdates(fn: (a: A) => R, a: A): R {
export function flushSync(fn: A => R, a: A): R {
const prevExecutionContext = executionContext;
+ if ((prevExecutionContext & (RenderContext | CommitContext)) !== NoContext) {
+ if (__DEV__) {
+ console.error(
+ 'flushSync was called from inside a lifecycle method. React cannot ' +
+ 'flush when React is already rendering. Consider moving this call to ' +
+ 'a scheduler task or micro task.',
+ );
+ }
+ return fn(a);
+ }
executionContext |= BatchedContext;
const previousPriority = getCurrentUpdatePriority();
@@ -1158,17 +1168,7 @@ export function flushSync(fn: A => R, a: A): R {
// Flush the immediate callbacks that were scheduled during this batch.
// Note that this will happen even if batchedUpdates is higher up
// the stack.
- if ((executionContext & (RenderContext | CommitContext)) === NoContext) {
- flushSyncCallbacks();
- } else {
- if (__DEV__) {
- console.error(
- 'flushSync was called from inside a lifecycle method. React cannot ' +
- 'flush when React is already rendering. Consider moving this call to ' +
- 'a scheduler task or micro task.',
- );
- }
- }
+ flushSyncCallbacks();
}
}
diff --git a/packages/react-reconciler/src/__tests__/ReactFlushSync-test.js b/packages/react-reconciler/src/__tests__/ReactFlushSync-test.js
deleted file mode 100644
index f763e44705aaa..0000000000000
--- a/packages/react-reconciler/src/__tests__/ReactFlushSync-test.js
+++ /dev/null
@@ -1,64 +0,0 @@
-let React;
-let ReactNoop;
-let Scheduler;
-let useState;
-let useEffect;
-
-describe('ReactFlushSync', () => {
- beforeEach(() => {
- jest.resetModules();
-
- React = require('react');
- ReactNoop = require('react-noop-renderer');
- Scheduler = require('scheduler');
- useState = React.useState;
- useEffect = React.useEffect;
- });
-
- function Text({text}) {
- Scheduler.unstable_yieldValue(text);
- return text;
- }
-
- // @gate experimental || !enableSyncDefaultUpdates
- test('changes priority of updates in useEffect', async () => {
- function App() {
- const [syncState, setSyncState] = useState(0);
- const [state, setState] = useState(0);
- useEffect(() => {
- if (syncState !== 1) {
- setState(1);
- ReactNoop.flushSync(() => setSyncState(1));
- }
- }, [syncState, state]);
- return ;
- }
-
- const root = ReactNoop.createRoot();
- await ReactNoop.act(async () => {
- if (gate(flags => flags.enableSyncDefaultUpdates)) {
- React.unstable_startTransition(() => {
- root.render();
- });
- } else {
- root.render();
- }
- // This will yield right before the passive effect fires
- expect(Scheduler).toFlushUntilNextPaint(['0, 0']);
-
- // The passive effect will schedule a sync update and a normal update.
- // They should commit in two separate batches. First the sync one.
- expect(() => {
- expect(Scheduler).toFlushUntilNextPaint(['1, 0']);
- }).toErrorDev('flushSync was called from inside a lifecycle method');
-
- // The remaining update is not sync
- ReactNoop.flushSync();
- expect(Scheduler).toHaveYielded([]);
-
- // Now flush it.
- expect(Scheduler).toFlushUntilNextPaint(['1, 1']);
- });
- expect(root).toMatchRenderedOutput('1, 1');
- });
-});