diff --git a/packages/react-dom/src/__tests__/ReactDOMHooks-test.js b/packages/react-dom/src/__tests__/ReactDOMHooks-test.js
index 896c8c0acac01..aff3003fc0ceb 100644
--- a/packages/react-dom/src/__tests__/ReactDOMHooks-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMHooks-test.js
@@ -53,32 +53,23 @@ describe('ReactDOMHooks', () => {
return 3 * n;
}
- // we explicitly catch the missing act() warnings
- // to simulate this tricky repro
- expect(() => {
- ReactDOM.render(, container);
- expect(container.textContent).toBe('1');
- expect(container2.textContent).toBe('');
- expect(container3.textContent).toBe('');
- Scheduler.unstable_flushAll();
- expect(container.textContent).toBe('1');
- expect(container2.textContent).toBe('2');
- expect(container3.textContent).toBe('3');
-
- ReactDOM.render(, container);
- expect(container.textContent).toBe('2');
- expect(container2.textContent).toBe('2'); // Not flushed yet
- expect(container3.textContent).toBe('3'); // Not flushed yet
- Scheduler.unstable_flushAll();
- expect(container.textContent).toBe('2');
- expect(container2.textContent).toBe('4');
- expect(container3.textContent).toBe('6');
- }).toWarnDev([
- 'An update to Example1 ran an effect',
- 'An update to Example2 ran an effect',
- 'An update to Example1 ran an effect',
- 'An update to Example2 ran an effect',
- ]);
+ ReactDOM.render(, container);
+ expect(container.textContent).toBe('1');
+ expect(container2.textContent).toBe('');
+ expect(container3.textContent).toBe('');
+ Scheduler.unstable_flushAll();
+ expect(container.textContent).toBe('1');
+ expect(container2.textContent).toBe('2');
+ expect(container3.textContent).toBe('3');
+
+ ReactDOM.render(, container);
+ expect(container.textContent).toBe('2');
+ expect(container2.textContent).toBe('2'); // Not flushed yet
+ expect(container3.textContent).toBe('3'); // Not flushed yet
+ Scheduler.unstable_flushAll();
+ expect(container.textContent).toBe('2');
+ expect(container2.textContent).toBe('4');
+ expect(container3.textContent).toBe('6');
});
it('should not bail out when an update is scheduled from within an event handler', () => {
diff --git a/packages/react-dom/src/__tests__/ReactTestUtilsAct-test.js b/packages/react-dom/src/__tests__/ReactTestUtilsAct-test.js
index fb1027a306289..ac37e5ba07ac9 100644
--- a/packages/react-dom/src/__tests__/ReactTestUtilsAct-test.js
+++ b/packages/react-dom/src/__tests__/ReactTestUtilsAct-test.js
@@ -48,6 +48,20 @@ describe('ReactTestUtils.act()', () => {
ReactDOM.unmountComponentAtNode(dom);
}
runActTests('legacy sync mode', renderSync, unmountSync);
+
+ // and then in batched mode
+ let batchedRoot;
+ function renderBatched(el, dom) {
+ batchedRoot = ReactDOM.unstable_createSyncRoot(dom);
+ batchedRoot.render(el);
+ }
+ function unmountBatched(dom) {
+ if (batchedRoot !== null) {
+ batchedRoot.unmount();
+ batchedRoot = null;
+ }
+ }
+ runActTests('batched mode', renderBatched, unmountBatched);
});
function runActTests(label, render, unmount) {
@@ -68,6 +82,26 @@ function runActTests(label, render, unmount) {
document.body.removeChild(container);
});
describe('sync', () => {
+ it('warns if an effect is queued outside an act scope, except in legacy sync+non-strict mode', () => {
+ function App() {
+ React.useEffect(() => {}, []);
+ return null;
+ }
+ expect(() => {
+ render(, container);
+ // flush all queued work
+ Scheduler.unstable_flushAll();
+ }).toWarnDev(
+ label !== 'legacy sync mode'
+ ? [
+ // warns twice because we're in strict+dev mode
+ 'An update to App ran an effect, but was not wrapped in act(...)',
+ 'An update to App ran an effect, but was not wrapped in act(...)',
+ ]
+ : [],
+ );
+ });
+
it('can use act to flush effects', () => {
function App() {
React.useEffect(() => {
diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js
index 1c5d14651fc27..f8a389e63577b 100644
--- a/packages/react-reconciler/src/ReactFiberWorkLoop.js
+++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js
@@ -2453,6 +2453,7 @@ export function warnIfNotCurrentlyActingEffectsInDEV(fiber: Fiber): void {
if (__DEV__) {
if (
warnsIfNotActing === true &&
+ fiber.mode &&
IsSomeRendererActing.current === false &&
IsThisRendererActing.current === false
) {
diff --git a/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js b/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js
index e0022d0a70c22..eff2904158a72 100644
--- a/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js
+++ b/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js
@@ -1806,7 +1806,6 @@ describe('ReactHooks', () => {
globalListener();
globalListener();
}).toWarnDev([
- 'An update to C ran an effect',
'An update to C inside a test was not wrapped in act',
'An update to C inside a test was not wrapped in act',
// Note: should *not* warn about updates on unmounted component.