Skip to content

Commit d17c220

Browse files
committed
allow nested acts from different renderers
sometimes apps can be made wtih multiple renderers. a specific usecase is react-art embedded inside react-dom. in these cases, we want to be able to wrap an update with acts corrsponding to both the renderers. In this PR, we change ReactCurrentActingRendererSigil to hold a stack of sigils (instead of just the current active one), pushing and popping onto it as required. This commit also fixes the dom fixtures tests, which were broken? ugh.
1 parent eb2ace1 commit d17c220

File tree

7 files changed

+28
-23
lines changed

7 files changed

+28
-23
lines changed

fixtures/dom/src/index.test.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import ARTSVGMode from 'art/modes/svg';
1414
import ARTCurrentMode from 'art/modes/current';
1515
import TestUtils from 'react-dom/test-utils';
1616
import TestRenderer from 'react-test-renderer';
17-
1817
ARTCurrentMode.setCurrent(ARTSVGMode);
1918

2019
global.__DEV__ = process.env.NODE_ENV !== 'production';
@@ -158,3 +157,11 @@ it('does not warn when nesting react-act inside react-test-renderer', () => {
158157
TestRenderer.create(<ARTTest />);
159158
});
160159
});
160+
161+
it("doesn't warn if you use nested acts from different renderers", () => {
162+
TestRenderer.act(() => {
163+
TestUtils.act(() => {
164+
TestRenderer.create(<App />);
165+
});
166+
});
167+
});

packages/react-dom/src/test-utils/ReactTestUtilsAct.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,17 +86,15 @@ let actingUpdatesScopeDepth = 0;
8686

8787
function act(callback: () => Thenable) {
8888
let previousActingUpdatesScopeDepth = actingUpdatesScopeDepth;
89-
let previousActingUpdatesSigil;
9089
actingUpdatesScopeDepth++;
9190
if (__DEV__) {
92-
previousActingUpdatesSigil = ReactCurrentActingRendererSigil.current;
93-
ReactCurrentActingRendererSigil.current = ReactActingRendererSigil;
91+
ReactCurrentActingRendererSigil.current.push(ReactActingRendererSigil);
9492
}
9593

9694
function onDone() {
9795
actingUpdatesScopeDepth--;
9896
if (__DEV__) {
99-
ReactCurrentActingRendererSigil.current = previousActingUpdatesSigil;
97+
ReactCurrentActingRendererSigil.current.pop();
10098
if (actingUpdatesScopeDepth > previousActingUpdatesScopeDepth) {
10199
// if it's _less than_ previousActingUpdatesScopeDepth, then we can assume the 'other' one has warned
102100
warningWithoutStack(

packages/react-noop-renderer/src/createReactNoop.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -615,17 +615,15 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
615615

616616
function act(callback: () => Thenable) {
617617
let previousActingUpdatesScopeDepth = actingUpdatesScopeDepth;
618-
let previousActingUpdatesSigil;
619618
actingUpdatesScopeDepth++;
620619
if (__DEV__) {
621-
previousActingUpdatesSigil = ReactCurrentActingRendererSigil.current;
622-
ReactCurrentActingRendererSigil.current = ReactActingRendererSigil;
620+
ReactCurrentActingRendererSigil.current.push(ReactActingRendererSigil);
623621
}
624622

625623
function onDone() {
626624
actingUpdatesScopeDepth--;
627625
if (__DEV__) {
628-
ReactCurrentActingRendererSigil.current = previousActingUpdatesSigil;
626+
ReactCurrentActingRendererSigil.current.pop();
629627
if (actingUpdatesScopeDepth > previousActingUpdatesScopeDepth) {
630628
// if it's _less than_ previousActingUpdatesScopeDepth, then we can assume the 'other' one has warned
631629
warningWithoutStack(

packages/react-reconciler/src/ReactFiberWorkLoop.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2422,8 +2422,10 @@ export function warnIfNotScopedWithMatchingAct(fiber: Fiber): void {
24222422
if (__DEV__) {
24232423
if (
24242424
shouldWarnUnactedUpdates === true &&
2425-
ReactCurrentActingRendererSigil.current !== null &&
2426-
ReactCurrentActingRendererSigil.current !== ReactActingRendererSigil
2425+
ReactCurrentActingRendererSigil.current.length !== 0 &&
2426+
ReactCurrentActingRendererSigil.current.indexOf(
2427+
ReactActingRendererSigil,
2428+
) === -1
24272429
) {
24282430
warningWithoutStack(
24292431
false,
@@ -2449,7 +2451,9 @@ export function warnIfNotCurrentlyActingEffectsInDEV(fiber: Fiber): void {
24492451
if (__DEV__) {
24502452
if (
24512453
shouldWarnUnactedUpdates === true &&
2452-
ReactCurrentActingRendererSigil.current !== ReactActingRendererSigil
2454+
ReactCurrentActingRendererSigil.current.indexOf(
2455+
ReactActingRendererSigil,
2456+
) === -1
24532457
) {
24542458
warningWithoutStack(
24552459
false,
@@ -2476,7 +2480,9 @@ function warnIfNotCurrentlyActingUpdatesInDEV(fiber: Fiber): void {
24762480
if (
24772481
shouldWarnUnactedUpdates === true &&
24782482
executionContext === NoContext &&
2479-
ReactCurrentActingRendererSigil.current !== ReactActingRendererSigil
2483+
ReactCurrentActingRendererSigil.current.indexOf(
2484+
ReactActingRendererSigil,
2485+
) === -1
24802486
) {
24812487
warningWithoutStack(
24822488
false,

packages/react-reconciler/src/__tests__/ReactNoopRendererAct-test.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ describe('ReactNoop.act()', () => {
3131
/>,
3232
);
3333
});
34-
expect(Scheduler).toFlushWithoutYielding();
3534
expect(calledLog).toEqual([0]);
3635
});
3736

@@ -54,7 +53,6 @@ describe('ReactNoop.act()', () => {
5453
ReactNoop.render(<App />);
5554
});
5655
expect(Scheduler).toHaveYielded(['stage 1', 'stage 2']);
57-
expect(Scheduler).toFlushWithoutYielding();
5856
expect(ReactNoop.getChildren()).toEqual([{text: '1', hidden: false}]);
5957
});
6058
});

packages/react-test-renderer/src/ReactTestRendererAct.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,17 +67,15 @@ let actingUpdatesScopeDepth = 0;
6767

6868
function act(callback: () => Thenable) {
6969
let previousActingUpdatesScopeDepth = actingUpdatesScopeDepth;
70-
let previousActingUpdatesSigil;
7170
actingUpdatesScopeDepth++;
7271
if (__DEV__) {
73-
previousActingUpdatesSigil = ReactCurrentActingRendererSigil.current;
74-
ReactCurrentActingRendererSigil.current = ReactActingRendererSigil;
72+
ReactCurrentActingRendererSigil.current.push(ReactActingRendererSigil);
7573
}
7674

7775
function onDone() {
7876
actingUpdatesScopeDepth--;
7977
if (__DEV__) {
80-
ReactCurrentActingRendererSigil.current = previousActingUpdatesSigil;
78+
ReactCurrentActingRendererSigil.current.pop();
8179
if (actingUpdatesScopeDepth > previousActingUpdatesScopeDepth) {
8280
// if it's _less than_ previousActingUpdatesScopeDepth, then we can assume the 'other' one has warned
8381
warningWithoutStack(

packages/react/src/ReactCurrentActingRendererSigil.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88
*/
99

1010
/**
11-
* Used by act() to track whether you're outside an act() scope.
12-
* We use a renderer's flushPassiveEffects as the sigil value
13-
* so we can track identity of the renderer.
11+
* We maintain a 'stack' of renderer specific sigils
12+
* corresponding to act() calls, so we can track whenever an update
13+
* happens inside/outside of one.
1414
*/
1515

1616
const ReactCurrentActingRendererSigil = {
17-
current: (null: null | (() => boolean)),
17+
current: ([]: Array<{}>),
1818
};
1919
export default ReactCurrentActingRendererSigil;

0 commit comments

Comments
 (0)