diff --git a/fixtures/dom/src/index.test.js b/fixtures/dom/src/index.test.js
index ad10e99d36b7b..fbf2aa8e36f30 100644
--- a/fixtures/dom/src/index.test.js
+++ b/fixtures/dom/src/index.test.js
@@ -14,7 +14,6 @@ import ARTSVGMode from 'art/modes/svg';
import ARTCurrentMode from 'art/modes/current';
import TestUtils from 'react-dom/test-utils';
import TestRenderer from 'react-test-renderer';
-
ARTCurrentMode.setCurrent(ARTSVGMode);
global.__DEV__ = process.env.NODE_ENV !== 'production';
@@ -158,3 +157,11 @@ it('does not warn when nesting react-act inside react-test-renderer', () => {
TestRenderer.create();
});
});
+
+it("doesn't warn if you use nested acts from different renderers", () => {
+ TestRenderer.act(() => {
+ TestUtils.act(() => {
+ TestRenderer.create();
+ });
+ });
+});
diff --git a/packages/react-dom/src/test-utils/ReactTestUtilsAct.js b/packages/react-dom/src/test-utils/ReactTestUtilsAct.js
index c12f396795966..0f43cca235a4d 100644
--- a/packages/react-dom/src/test-utils/ReactTestUtilsAct.js
+++ b/packages/react-dom/src/test-utils/ReactTestUtilsAct.js
@@ -86,17 +86,15 @@ let actingUpdatesScopeDepth = 0;
function act(callback: () => Thenable) {
let previousActingUpdatesScopeDepth = actingUpdatesScopeDepth;
- let previousActingUpdatesSigil;
actingUpdatesScopeDepth++;
if (__DEV__) {
- previousActingUpdatesSigil = ReactCurrentActingRendererSigil.current;
- ReactCurrentActingRendererSigil.current = ReactActingRendererSigil;
+ ReactCurrentActingRendererSigil.current.push(ReactActingRendererSigil);
}
function onDone() {
actingUpdatesScopeDepth--;
if (__DEV__) {
- ReactCurrentActingRendererSigil.current = previousActingUpdatesSigil;
+ ReactCurrentActingRendererSigil.current.pop();
if (actingUpdatesScopeDepth > previousActingUpdatesScopeDepth) {
// if it's _less than_ previousActingUpdatesScopeDepth, then we can assume the 'other' one has warned
warningWithoutStack(
diff --git a/packages/react-noop-renderer/src/createReactNoop.js b/packages/react-noop-renderer/src/createReactNoop.js
index f1d7fc419548d..b60703a761796 100644
--- a/packages/react-noop-renderer/src/createReactNoop.js
+++ b/packages/react-noop-renderer/src/createReactNoop.js
@@ -615,17 +615,15 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
function act(callback: () => Thenable) {
let previousActingUpdatesScopeDepth = actingUpdatesScopeDepth;
- let previousActingUpdatesSigil;
actingUpdatesScopeDepth++;
if (__DEV__) {
- previousActingUpdatesSigil = ReactCurrentActingRendererSigil.current;
- ReactCurrentActingRendererSigil.current = ReactActingRendererSigil;
+ ReactCurrentActingRendererSigil.current.push(ReactActingRendererSigil);
}
function onDone() {
actingUpdatesScopeDepth--;
if (__DEV__) {
- ReactCurrentActingRendererSigil.current = previousActingUpdatesSigil;
+ ReactCurrentActingRendererSigil.current.pop();
if (actingUpdatesScopeDepth > previousActingUpdatesScopeDepth) {
// if it's _less than_ previousActingUpdatesScopeDepth, then we can assume the 'other' one has warned
warningWithoutStack(
diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js
index 1308452a77850..9eabc8756dd39 100644
--- a/packages/react-reconciler/src/ReactFiberWorkLoop.js
+++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js
@@ -2422,8 +2422,10 @@ export function warnIfNotScopedWithMatchingAct(fiber: Fiber): void {
if (__DEV__) {
if (
shouldWarnUnactedUpdates === true &&
- ReactCurrentActingRendererSigil.current !== null &&
- ReactCurrentActingRendererSigil.current !== ReactActingRendererSigil
+ ReactCurrentActingRendererSigil.current.length !== 0 &&
+ ReactCurrentActingRendererSigil.current.indexOf(
+ ReactActingRendererSigil,
+ ) === -1
) {
warningWithoutStack(
false,
@@ -2449,7 +2451,9 @@ export function warnIfNotCurrentlyActingEffectsInDEV(fiber: Fiber): void {
if (__DEV__) {
if (
shouldWarnUnactedUpdates === true &&
- ReactCurrentActingRendererSigil.current !== ReactActingRendererSigil
+ ReactCurrentActingRendererSigil.current.indexOf(
+ ReactActingRendererSigil,
+ ) === -1
) {
warningWithoutStack(
false,
@@ -2476,7 +2480,9 @@ function warnIfNotCurrentlyActingUpdatesInDEV(fiber: Fiber): void {
if (
shouldWarnUnactedUpdates === true &&
executionContext === NoContext &&
- ReactCurrentActingRendererSigil.current !== ReactActingRendererSigil
+ ReactCurrentActingRendererSigil.current.indexOf(
+ ReactActingRendererSigil,
+ ) === -1
) {
warningWithoutStack(
false,
diff --git a/packages/react-reconciler/src/__tests__/ReactNoopRendererAct-test.js b/packages/react-reconciler/src/__tests__/ReactNoopRendererAct-test.js
index 38be78044cc8e..6b7c0103a9f41 100644
--- a/packages/react-reconciler/src/__tests__/ReactNoopRendererAct-test.js
+++ b/packages/react-reconciler/src/__tests__/ReactNoopRendererAct-test.js
@@ -31,7 +31,6 @@ describe('ReactNoop.act()', () => {
/>,
);
});
- expect(Scheduler).toFlushWithoutYielding();
expect(calledLog).toEqual([0]);
});
@@ -54,7 +53,6 @@ describe('ReactNoop.act()', () => {
ReactNoop.render();
});
expect(Scheduler).toHaveYielded(['stage 1', 'stage 2']);
- expect(Scheduler).toFlushWithoutYielding();
expect(ReactNoop.getChildren()).toEqual([{text: '1', hidden: false}]);
});
});
diff --git a/packages/react-test-renderer/src/ReactTestRendererAct.js b/packages/react-test-renderer/src/ReactTestRendererAct.js
index 1e47e33583a52..8ffd52f66c501 100644
--- a/packages/react-test-renderer/src/ReactTestRendererAct.js
+++ b/packages/react-test-renderer/src/ReactTestRendererAct.js
@@ -67,17 +67,15 @@ let actingUpdatesScopeDepth = 0;
function act(callback: () => Thenable) {
let previousActingUpdatesScopeDepth = actingUpdatesScopeDepth;
- let previousActingUpdatesSigil;
actingUpdatesScopeDepth++;
if (__DEV__) {
- previousActingUpdatesSigil = ReactCurrentActingRendererSigil.current;
- ReactCurrentActingRendererSigil.current = ReactActingRendererSigil;
+ ReactCurrentActingRendererSigil.current.push(ReactActingRendererSigil);
}
function onDone() {
actingUpdatesScopeDepth--;
if (__DEV__) {
- ReactCurrentActingRendererSigil.current = previousActingUpdatesSigil;
+ ReactCurrentActingRendererSigil.current.pop();
if (actingUpdatesScopeDepth > previousActingUpdatesScopeDepth) {
// if it's _less than_ previousActingUpdatesScopeDepth, then we can assume the 'other' one has warned
warningWithoutStack(
diff --git a/packages/react/src/ReactCurrentActingRendererSigil.js b/packages/react/src/ReactCurrentActingRendererSigil.js
index 09e05c8362d7b..c579464b7f67c 100644
--- a/packages/react/src/ReactCurrentActingRendererSigil.js
+++ b/packages/react/src/ReactCurrentActingRendererSigil.js
@@ -8,12 +8,12 @@
*/
/**
- * Used by act() to track whether you're outside an act() scope.
- * We use a renderer's flushPassiveEffects as the sigil value
- * so we can track identity of the renderer.
+ * We maintain a 'stack' of renderer specific sigils
+ * corresponding to act() calls, so we can track whenever an update
+ * happens inside/outside of one.
*/
const ReactCurrentActingRendererSigil = {
- current: (null: null | (() => boolean)),
+ current: ([]: Array<{}>),
};
export default ReactCurrentActingRendererSigil;