Skip to content

Commit 4dc279d

Browse files
Sunil Paitrueadm
authored andcommitted
allow nested act()s from different renderers (facebook#16039)
* allow nested `act()`s from different renderers There are usecases where multiple renderers need to oprate inside an act() scope - ReactDOM.render being used inside another component tree. The parent component will be rendered using ReactTestRenderer.create for a snapshot test or something. - a ReactDOM instance interacting with a ReactTestRenderer instance (like for the new devtools) This PR changes the way the acting sigils operate to allow for this. It keeps 2 booleans, one attached to React, one attached to the renderer. act() changes these values, and the workloop reads them to decide what warning to trigger. I also renamed shouldWarnUnactedUpdates to warnsIfNotActing * s/ReactIsActing/IsSomeRendererActing and s/ReactRendererIsActing/IsThisRendererActing
1 parent 068b86b commit 4dc279d

File tree

18 files changed

+85
-75
lines changed

18 files changed

+85
-75
lines changed

fixtures/dom/src/index.test.js

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,7 @@ it('warns when using the wrong act version - test + dom: updates', () => {
7070
TestRenderer.act(() => {
7171
setCtr(1);
7272
});
73-
}).toWarnDev([
74-
'An update to Counter inside a test was not wrapped in act',
75-
"It looks like you're using the wrong act()",
76-
]);
73+
}).toWarnDev(["It looks like you're using the wrong act()"]);
7774
});
7875

7976
it('warns when using the wrong act version - dom + test: .create()', () => {
@@ -109,10 +106,7 @@ it('warns when using the wrong act version - dom + test: updates', () => {
109106
TestUtils.act(() => {
110107
setCtr(1);
111108
});
112-
}).toWarnDev([
113-
'An update to Counter inside a test was not wrapped in act',
114-
"It looks like you're using the wrong act()",
115-
]);
109+
}).toWarnDev(["It looks like you're using the wrong act()"]);
116110
});
117111

118112
const {Surface, Group, Shape} = ReactART;
@@ -158,3 +152,11 @@ it('does not warn when nesting react-act inside react-test-renderer', () => {
158152
TestRenderer.create(<ARTTest />);
159153
});
160154
});
155+
156+
it("doesn't warn if you use nested acts from different renderers", () => {
157+
TestRenderer.act(() => {
158+
TestUtils.act(() => {
159+
TestRenderer.create(<App />);
160+
});
161+
});
162+
});

packages/react-art/src/ReactARTHostConfig.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ export function shouldSetTextContent(type, props) {
347347
export const isPrimaryRenderer = false;
348348

349349
// The ART renderer shouldn't trigger missing act() warnings
350-
export const shouldWarnUnactedUpdates = false;
350+
export const warnsIfNotActing = false;
351351

352352
export const supportsMutation = true;
353353

packages/react-dom/src/client/ReactDOM.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ import {
3838
findHostInstance,
3939
findHostInstanceWithWarning,
4040
flushPassiveEffects,
41-
ReactActingRendererSigil,
41+
IsThisRendererActing,
4242
} from 'react-reconciler/inline.dom';
4343
import {createPortal as createPortalImpl} from 'shared/ReactPortal';
4444
import {canUseDOM} from 'shared/ExecutionEnvironment';
@@ -817,7 +817,7 @@ const ReactDOM: Object = {
817817
dispatchEvent,
818818
runEventsInBatch,
819819
flushPassiveEffects,
820-
ReactActingRendererSigil,
820+
IsThisRendererActing,
821821
],
822822
},
823823
};

packages/react-dom/src/client/ReactDOMHostConfig.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ export function createTextInstance(
348348
}
349349

350350
export const isPrimaryRenderer = true;
351-
export const shouldWarnUnactedUpdates = true;
351+
export const warnsIfNotActing = true;
352352
// This initialization code may run even on server environments
353353
// if a component just imports ReactDOM (e.g. for findDOMNode).
354354
// Some environments might not have setTimeout or clearTimeout.

packages/react-dom/src/fire/ReactFire.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ import {
4343
findHostInstance,
4444
findHostInstanceWithWarning,
4545
flushPassiveEffects,
46-
ReactActingRendererSigil,
46+
IsThisRendererActing,
4747
} from 'react-reconciler/inline.fire';
4848
import {createPortal as createPortalImpl} from 'shared/ReactPortal';
4949
import {canUseDOM} from 'shared/ExecutionEnvironment';
@@ -823,7 +823,7 @@ const ReactDOM: Object = {
823823
dispatchEvent,
824824
runEventsInBatch,
825825
flushPassiveEffects,
826-
ReactActingRendererSigil,
826+
IsThisRendererActing,
827827
],
828828
},
829829
};

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ const [
4444
runEventsInBatch,
4545
/* eslint-disable no-unused-vars */
4646
flushPassiveEffects,
47-
ReactActingRendererSigil,
47+
IsThisRendererActing,
4848
/* eslint-enable no-unused-vars */
4949
] = ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Events;
5050

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

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@ const [
3333
runEventsInBatch,
3434
/* eslint-enable no-unused-vars */
3535
flushPassiveEffects,
36-
ReactActingRendererSigil,
36+
IsThisRendererActing,
3737
] = ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Events;
3838

3939
const batchedUpdates = ReactDOM.unstable_batchedUpdates;
4040

41-
const {ReactCurrentActingRendererSigil} = ReactSharedInternals;
41+
const {IsSomeRendererActing} = ReactSharedInternals;
4242

4343
// this implementation should be exactly the same in
4444
// ReactTestUtilsAct.js, ReactTestRendererAct.js, createReactNoop.js
@@ -86,17 +86,21 @@ let actingUpdatesScopeDepth = 0;
8686

8787
function act(callback: () => Thenable) {
8888
let previousActingUpdatesScopeDepth = actingUpdatesScopeDepth;
89-
let previousActingUpdatesSigil;
89+
let previousIsSomeRendererActing;
90+
let previousIsThisRendererActing;
9091
actingUpdatesScopeDepth++;
9192
if (__DEV__) {
92-
previousActingUpdatesSigil = ReactCurrentActingRendererSigil.current;
93-
ReactCurrentActingRendererSigil.current = ReactActingRendererSigil;
93+
previousIsSomeRendererActing = IsSomeRendererActing.current;
94+
previousIsThisRendererActing = IsSomeRendererActing.current;
95+
IsSomeRendererActing.current = true;
96+
IsThisRendererActing.current = true;
9497
}
9598

9699
function onDone() {
97100
actingUpdatesScopeDepth--;
98101
if (__DEV__) {
99-
ReactCurrentActingRendererSigil.current = previousActingUpdatesSigil;
102+
IsSomeRendererActing.current = previousIsSomeRendererActing;
103+
IsThisRendererActing.current = previousIsThisRendererActing;
100104
if (actingUpdatesScopeDepth > previousActingUpdatesScopeDepth) {
101105
// if it's _less than_ previousActingUpdatesScopeDepth, then we can assume the 'other' one has warned
102106
warningWithoutStack(

packages/react-native-renderer/src/ReactFabricHostConfig.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ export function shouldSetTextContent(type: string, props: Props): boolean {
352352
export const isPrimaryRenderer = false;
353353

354354
// The Fabric renderer shouldn't trigger missing act() warnings
355-
export const shouldWarnUnactedUpdates = false;
355+
export const warnsIfNotActing = false;
356356

357357
export const scheduleTimeout = setTimeout;
358358
export const cancelTimeout = clearTimeout;

packages/react-native-renderer/src/ReactNativeHostConfig.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ export function resetAfterCommit(containerInfo: Container): void {
247247
}
248248

249249
export const isPrimaryRenderer = true;
250-
export const shouldWarnUnactedUpdates = true;
250+
export const warnsIfNotActing = true;
251251

252252
export const scheduleTimeout = setTimeout;
253253
export const cancelTimeout = clearTimeout;

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

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ type TextInstance = {|
6565
|};
6666
type HostContext = Object;
6767

68-
const {ReactCurrentActingRendererSigil} = ReactSharedInternals;
68+
const {IsSomeRendererActing} = ReactSharedInternals;
6969

7070
const NO_CONTEXT = {};
7171
const UPPERCASE_CONTEXT = {};
@@ -393,7 +393,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
393393
now: Scheduler.unstable_now,
394394

395395
isPrimaryRenderer: true,
396-
shouldWarnUnactedUpdates: true,
396+
warnsIfNotActing: true,
397397
supportsHydration: false,
398398

399399
mountEventComponent(): void {
@@ -566,7 +566,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
566566
const {
567567
flushPassiveEffects,
568568
batchedUpdates,
569-
ReactActingRendererSigil,
569+
IsThisRendererActing,
570570
} = NoopRenderer;
571571

572572
// this act() implementation should be exactly the same in
@@ -615,17 +615,21 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
615615

616616
function act(callback: () => Thenable) {
617617
let previousActingUpdatesScopeDepth = actingUpdatesScopeDepth;
618-
let previousActingUpdatesSigil;
618+
let previousIsSomeRendererActing;
619+
let previousIsThisRendererActing;
619620
actingUpdatesScopeDepth++;
620621
if (__DEV__) {
621-
previousActingUpdatesSigil = ReactCurrentActingRendererSigil.current;
622-
ReactCurrentActingRendererSigil.current = ReactActingRendererSigil;
622+
previousIsSomeRendererActing = IsSomeRendererActing.current;
623+
previousIsThisRendererActing = IsSomeRendererActing.current;
624+
IsSomeRendererActing.current = true;
625+
IsThisRendererActing.current = true;
623626
}
624627

625628
function onDone() {
626629
actingUpdatesScopeDepth--;
627630
if (__DEV__) {
628-
ReactCurrentActingRendererSigil.current = previousActingUpdatesSigil;
631+
IsSomeRendererActing.current = previousIsSomeRendererActing;
632+
IsThisRendererActing.current = previousIsThisRendererActing;
629633
if (actingUpdatesScopeDepth > previousActingUpdatesScopeDepth) {
630634
// if it's _less than_ previousActingUpdatesScopeDepth, then we can assume the 'other' one has warned
631635
warningWithoutStack(

0 commit comments

Comments
 (0)