diff --git a/packages/react-dom/src/__tests__/ReactDOMHooks-test.js b/packages/react-dom/src/__tests__/ReactDOMHooks-test.js
index 399751cb7ef62..fe6caa82198da 100644
--- a/packages/react-dom/src/__tests__/ReactDOMHooks-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMHooks-test.js
@@ -70,6 +70,42 @@ describe('ReactDOMHooks', () => {
expect(container3.textContent).toBe('6');
});
+ it('can batch synchronous work inside effects with other work', () => {
+ let otherContainer = document.createElement('div');
+
+ let calledA = false;
+ function A() {
+ calledA = true;
+ return 'A';
+ }
+
+ let calledB = false;
+ function B() {
+ calledB = true;
+ return 'B';
+ }
+
+ let _set;
+ function Foo() {
+ _set = React.useState(0)[1];
+ React.useEffect(() => {
+ ReactDOM.render(, otherContainer);
+ });
+ return null;
+ }
+
+ ReactDOM.render(, container);
+ ReactDOM.unstable_batchedUpdates(() => {
+ _set(0); // Forces the effect to be flushed
+ expect(otherContainer.textContent).toBe('');
+ ReactDOM.render(, otherContainer);
+ expect(otherContainer.textContent).toBe('');
+ });
+ expect(otherContainer.textContent).toBe('B');
+ expect(calledA).toBe(false); // It was in a batch
+ expect(calledB).toBe(true);
+ });
+
it('should not bail out when an update is scheduled from within an event handler', () => {
const {createRef, useCallback, useState} = React;
diff --git a/packages/react-reconciler/src/ReactFiberScheduler.js b/packages/react-reconciler/src/ReactFiberScheduler.js
index 783ec2ed272db..2e05987a3d3d4 100644
--- a/packages/react-reconciler/src/ReactFiberScheduler.js
+++ b/packages/react-reconciler/src/ReactFiberScheduler.js
@@ -573,7 +573,7 @@ function commitPassiveEffects(root: FiberRoot, firstEffect: Fiber): void {
requestWork(root, rootExpirationTime);
}
// Flush any sync work that was scheduled by effects
- if (!isRendering) {
+ if (!isBatchingUpdates && !isRendering) {
performSyncWork();
}
}