diff --git a/packages/react-dom/index.classic.fb.js b/packages/react-dom/index.classic.fb.js
index 65425ce24a235..a9efae8208b94 100644
--- a/packages/react-dom/index.classic.fb.js
+++ b/packages/react-dom/index.classic.fb.js
@@ -29,7 +29,6 @@ export {
unmountComponentAtNode,
unstable_batchedUpdates,
unstable_createEventHandle,
- unstable_flushControlled,
unstable_renderSubtreeIntoContainer,
unstable_runWithPriority, // DO NOT USE: Temporarily exposed to migrate off of Scheduler.runWithPriority.
prefetchDNS,
diff --git a/packages/react-dom/index.js b/packages/react-dom/index.js
index f57e1e97c9249..169db31142d9b 100644
--- a/packages/react-dom/index.js
+++ b/packages/react-dom/index.js
@@ -21,7 +21,6 @@ export {
unmountComponentAtNode,
unstable_batchedUpdates,
unstable_createEventHandle,
- unstable_flushControlled,
unstable_renderSubtreeIntoContainer,
unstable_runWithPriority, // DO NOT USE: Temporarily exposed to migrate off of Scheduler.runWithPriority.
prefetchDNS,
diff --git a/packages/react-dom/index.modern.fb.js b/packages/react-dom/index.modern.fb.js
index cac8ec594f7b5..c41519668d5a5 100644
--- a/packages/react-dom/index.modern.fb.js
+++ b/packages/react-dom/index.modern.fb.js
@@ -15,7 +15,6 @@ export {
flushSync,
unstable_batchedUpdates,
unstable_createEventHandle,
- unstable_flushControlled,
unstable_runWithPriority, // DO NOT USE: Temporarily exposed to migrate off of Scheduler.runWithPriority.
prefetchDNS,
preconnect,
diff --git a/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js b/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js
index c8d445264da9b..61bb7a318d617 100644
--- a/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js
@@ -306,101 +306,6 @@ describe('ReactDOMFiberAsync', () => {
expect(container.textContent).toEqual('ABCD');
});
- // @gate www
- it('flushControlled flushes updates before yielding to browser', async () => {
- let inst;
- class Counter extends React.Component {
- state = {counter: 0};
- increment = () =>
- this.setState(state => ({counter: state.counter + 1}));
- render() {
- inst = this;
- return this.state.counter;
- }
- }
- const root = ReactDOMClient.createRoot(container);
- await act(() => root.render());
- expect(container.textContent).toEqual('0');
-
- // Test that a normal update is async
- await act(() => {
- inst.increment();
- expect(container.textContent).toEqual('0');
- });
- expect(container.textContent).toEqual('1');
-
- const ops = [];
- ReactDOM.unstable_flushControlled(() => {
- inst.increment();
- ReactDOM.unstable_flushControlled(() => {
- inst.increment();
- ops.push('end of inner flush: ' + container.textContent);
- });
- ops.push('end of outer flush: ' + container.textContent);
- });
- ops.push('after outer flush: ' + container.textContent);
- expect(ops).toEqual([
- 'end of inner flush: 1',
- 'end of outer flush: 1',
- 'after outer flush: 3',
- ]);
- });
-
- // @gate www
- it('flushControlled does not flush until end of outermost batchedUpdates', () => {
- let inst;
- class Counter extends React.Component {
- state = {counter: 0};
- increment = () =>
- this.setState(state => ({counter: state.counter + 1}));
- render() {
- inst = this;
- return this.state.counter;
- }
- }
- ReactDOM.render(, container);
-
- const ops = [];
- ReactDOM.unstable_batchedUpdates(() => {
- inst.increment();
- ReactDOM.unstable_flushControlled(() => {
- inst.increment();
- ops.push('end of flushControlled fn: ' + container.textContent);
- });
- ops.push('end of batchedUpdates fn: ' + container.textContent);
- });
- ops.push('after batchedUpdates: ' + container.textContent);
- expect(ops).toEqual([
- 'end of flushControlled fn: 0',
- 'end of batchedUpdates fn: 0',
- 'after batchedUpdates: 2',
- ]);
- });
-
- // @gate www
- it('flushControlled returns nothing', () => {
- // In the future, we may want to return a thenable "work" object.
- let inst;
- class Counter extends React.Component {
- state = {counter: 0};
- increment = () =>
- this.setState(state => ({counter: state.counter + 1}));
- render() {
- inst = this;
- return this.state.counter;
- }
- }
- ReactDOM.render(, container);
- expect(container.textContent).toEqual('0');
-
- const returnValue = ReactDOM.unstable_flushControlled(() => {
- inst.increment();
- return 'something';
- });
- expect(container.textContent).toEqual('1');
- expect(returnValue).toBe(undefined);
- });
-
it('ignores discrete events on a pending removed element', async () => {
const disableButtonRef = React.createRef();
const submitButtonRef = React.createRef();
diff --git a/packages/react-dom/src/__tests__/react-dom-server-rendering-stub-test.js b/packages/react-dom/src/__tests__/react-dom-server-rendering-stub-test.js
index d51c166bf765d..8840a4f61a22a 100644
--- a/packages/react-dom/src/__tests__/react-dom-server-rendering-stub-test.js
+++ b/packages/react-dom/src/__tests__/react-dom-server-rendering-stub-test.js
@@ -35,7 +35,6 @@ describe('react-dom-server-rendering-stub', () => {
expect(ReactDOM.unmountComponentAtNode).toBe(undefined);
expect(ReactDOM.unstable_batchedUpdates).toBe(undefined);
expect(ReactDOM.unstable_createEventHandle).toBe(undefined);
- expect(ReactDOM.unstable_flushControlled).toBe(undefined);
expect(ReactDOM.unstable_renderSubtreeIntoContainer).toBe(undefined);
expect(ReactDOM.unstable_runWithPriority).toBe(undefined);
});
diff --git a/packages/react-dom/src/client/ReactDOM.js b/packages/react-dom/src/client/ReactDOM.js
index 42fcd1648f6ef..936fad8090110 100644
--- a/packages/react-dom/src/client/ReactDOM.js
+++ b/packages/react-dom/src/client/ReactDOM.js
@@ -36,7 +36,6 @@ import {
batchedUpdates,
flushSync as flushSyncWithoutWarningIfAlreadyRendering,
isAlreadyRendering,
- flushControlled,
injectIntoDevTools,
} from 'react-reconciler/src/ReactFiberReconciler';
import {runWithPriority} from 'react-reconciler/src/ReactEventPriorities';
@@ -173,7 +172,6 @@ export {
// exposeConcurrentModeAPIs
createRoot,
hydrateRoot,
- flushControlled as unstable_flushControlled,
// Disabled behind disableUnstableRenderSubtreeIntoContainer
renderSubtreeIntoContainer as unstable_renderSubtreeIntoContainer,
// enableCreateEventHandleAPI
diff --git a/packages/react-reconciler/src/ReactFiberReconciler.js b/packages/react-reconciler/src/ReactFiberReconciler.js
index 4842de3bc1ec4..0234aa38c7f6c 100644
--- a/packages/react-reconciler/src/ReactFiberReconciler.js
+++ b/packages/react-reconciler/src/ReactFiberReconciler.js
@@ -64,7 +64,6 @@ import {
batchedUpdates,
flushSync,
isAlreadyRendering,
- flushControlled,
deferredUpdates,
discreteUpdates,
flushPassiveEffects,
@@ -392,7 +391,6 @@ export {
batchedUpdates,
deferredUpdates,
discreteUpdates,
- flushControlled,
flushSync,
isAlreadyRendering,
flushPassiveEffects,
diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js
index 0bad69e81aa23..6459cd0775aa6 100644
--- a/packages/react-reconciler/src/ReactFiberWorkLoop.js
+++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js
@@ -1665,28 +1665,6 @@ export function isInvalidExecutionContextForEventFunction(): boolean {
return (executionContext & RenderContext) !== NoContext;
}
-export function flushControlled(fn: () => mixed): void {
- const prevExecutionContext = executionContext;
- executionContext |= BatchedContext;
- const prevTransition = ReactCurrentBatchConfig.transition;
- const previousPriority = getCurrentUpdatePriority();
- try {
- ReactCurrentBatchConfig.transition = null;
- setCurrentUpdatePriority(DiscreteEventPriority);
- fn();
- } finally {
- setCurrentUpdatePriority(previousPriority);
- ReactCurrentBatchConfig.transition = prevTransition;
-
- executionContext = prevExecutionContext;
- if (executionContext === NoContext) {
- // Flush the immediate callbacks that were scheduled during this batch
- resetRenderTimer();
- flushSyncCallbacks();
- }
- }
-}
-
// This is called by the HiddenContext module when we enter or leave a
// hidden subtree. The stack logic is managed there because that's the only
// place that ever modifies it. Which module it lives in doesn't matter for