diff --git a/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.internal.js b/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.internal.js
index 69013757ae8fb..c3e83a5795400 100644
--- a/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.internal.js
+++ b/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.internal.js
@@ -10,6 +10,7 @@
'use strict';
const React = require('react');
+const Fragment = React.Fragment;
let ReactFeatureFlags = require('shared/ReactFeatureFlags');
let ReactDOM;
@@ -659,4 +660,55 @@ describe('ReactDOMFiberAsync', () => {
expect(formSubmitted).toBe(true);
});
});
+
+ describe('Disable yielding', () => {
+ beforeEach(() => {
+ jest.resetModules();
+ ReactFeatureFlags = require('shared/ReactFeatureFlags');
+ ReactFeatureFlags.disableYielding = true;
+ ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false;
+ ReactDOM = require('react-dom');
+ Scheduler = require('scheduler');
+ });
+
+ it('wont yield during a render if yielding is disabled', () => {
+ class A extends React.Component {
+ render() {
+ Scheduler.yieldValue('A');
+ return
{this.props.children}
;
+ }
+ }
+
+ class B extends React.Component {
+ render() {
+ Scheduler.yieldValue('B');
+ return {this.props.children}
;
+ }
+ }
+
+ class C extends React.Component {
+ render() {
+ Scheduler.yieldValue('C');
+ return {this.props.children}
;
+ }
+ }
+
+ let root = ReactDOM.unstable_createRoot(container);
+
+ root.render(
+
+
+
+
+ ,
+ );
+
+ expect(Scheduler).toHaveYielded([]);
+
+ Scheduler.unstable_flushNumberOfYields(2);
+ // Even though we just flushed two yields, we should have rendered
+ // everything without yielding when the flag is on.
+ expect(Scheduler).toHaveYielded(['A', 'B', 'C']);
+ });
+ });
});
diff --git a/packages/react-reconciler/src/ReactFiberScheduler.js b/packages/react-reconciler/src/ReactFiberScheduler.js
index fdd42867b31d3..e24e2ad714803 100644
--- a/packages/react-reconciler/src/ReactFiberScheduler.js
+++ b/packages/react-reconciler/src/ReactFiberScheduler.js
@@ -63,6 +63,7 @@ import {
replayFailedUnitOfWorkWithInvokeGuardedCallback,
warnAboutDeprecatedLifecycles,
enableSuspenseServerRenderer,
+ disableYielding,
} from 'shared/ReactFeatureFlags';
import getComponentName from 'shared/getComponentName';
import invariant from 'shared/invariant';
@@ -2019,7 +2020,7 @@ function onSuspend(
msUntilTimeout: number,
): void {
root.expirationTime = rootExpirationTime;
- if (msUntilTimeout === 0 && !shouldYield()) {
+ if (msUntilTimeout === 0 && (disableYielding || !shouldYield())) {
// Don't wait an additional tick. Commit the tree immediately.
root.pendingCommitExpirationTime = suspendedExpirationTime;
root.finishedWork = finishedWork;
@@ -2233,7 +2234,11 @@ function performAsyncWork(didTimeout) {
} while (root !== firstScheduledRoot);
}
}
- performWork(NoWork, true);
+ let isYieldy = true;
+ if (disableYielding) {
+ isYieldy = false;
+ }
+ performWork(NoWork, isYieldy);
}
function performSyncWork() {
diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js
index b9e249914b1ad..95108e7d96239 100644
--- a/packages/shared/ReactFeatureFlags.js
+++ b/packages/shared/ReactFeatureFlags.js
@@ -45,6 +45,9 @@ export function addUserTimingListener() {
// Disable javascript: URL strings in href for XSS protection.
export const disableJavaScriptURLs = false;
+// Disables yielding during render in Concurrent Mode. Used for debugging only.
+export const disableYielding = false;
+
// React Fire: prevent the value and checked attributes from syncing
// with their related DOM properties
export const disableInputAttributeSyncing = false;
diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js
index c1de808b851bc..64db95b8d8484 100644
--- a/packages/shared/forks/ReactFeatureFlags.native-fb.js
+++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js
@@ -25,6 +25,7 @@ export const warnAboutShorthandPropertyCollision = false;
export const enableSchedulerDebugging = false;
export const debugRenderPhaseSideEffectsForStrictMode = true;
export const disableJavaScriptURLs = false;
+export const disableYielding = false;
export const disableInputAttributeSyncing = false;
export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__;
export const warnAboutDeprecatedLifecycles = true;
diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js
index edfe1f5e220d0..a5cfb3d29435d 100644
--- a/packages/shared/forks/ReactFeatureFlags.native-oss.js
+++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js
@@ -21,6 +21,7 @@ export const enableProfilerTimer = __PROFILE__;
export const enableSchedulerTracing = __PROFILE__;
export const enableSuspenseServerRenderer = false;
export const disableJavaScriptURLs = false;
+export const disableYielding = false;
export const disableInputAttributeSyncing = false;
export const enableStableConcurrentModeAPIs = false;
export const warnAboutShorthandPropertyCollision = false;
diff --git a/packages/shared/forks/ReactFeatureFlags.persistent.js b/packages/shared/forks/ReactFeatureFlags.persistent.js
index 7b8fb48083cbb..692864b4cfd57 100644
--- a/packages/shared/forks/ReactFeatureFlags.persistent.js
+++ b/packages/shared/forks/ReactFeatureFlags.persistent.js
@@ -21,6 +21,7 @@ export const enableProfilerTimer = __PROFILE__;
export const enableSchedulerTracing = __PROFILE__;
export const enableSuspenseServerRenderer = false;
export const disableJavaScriptURLs = false;
+export const disableYielding = false;
export const disableInputAttributeSyncing = false;
export const enableStableConcurrentModeAPIs = false;
export const warnAboutShorthandPropertyCollision = false;
diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.js
index 7153ac8c29903..7239941035bc5 100644
--- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js
+++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js
@@ -21,6 +21,7 @@ export const enableProfilerTimer = false;
export const enableSchedulerTracing = false;
export const enableSuspenseServerRenderer = false;
export const disableJavaScriptURLs = false;
+export const disableYielding = false;
export const disableInputAttributeSyncing = false;
export const enableStableConcurrentModeAPIs = false;
export const warnAboutShorthandPropertyCollision = false;
diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
index 660f3c19d754a..096494b839ef7 100644
--- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
+++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
@@ -24,6 +24,7 @@ export const enableStableConcurrentModeAPIs = false;
export const enableSchedulerDebugging = false;
export const warnAboutDeprecatedSetNativeProps = false;
export const disableJavaScriptURLs = false;
+export const disableYielding = false;
export const enableEventAPI = true;
// Only used in www builds.
diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js
index f967402adc871..e47428a52a3c3 100644
--- a/packages/shared/forks/ReactFeatureFlags.www.js
+++ b/packages/shared/forks/ReactFeatureFlags.www.js
@@ -17,6 +17,7 @@ export const {
replayFailedUnitOfWorkWithInvokeGuardedCallback,
warnAboutDeprecatedLifecycles,
disableJavaScriptURLs,
+ disableYielding,
disableInputAttributeSyncing,
warnAboutShorthandPropertyCollision,
warnAboutDeprecatedSetNativeProps,