Skip to content

Commit 2b05a31

Browse files
committed
Dim console calls when invoking effects due to StrictMode
1 parent 1d5ee2b commit 2b05a31

5 files changed

Lines changed: 93 additions & 20 deletions

File tree

packages/internal-test-utils/__tests__/ReactInternalTestUtils-test.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,12 @@ describe('ReactInternalTestUtils', () => {
146146
test('assertLog', async () => {
147147
const Yield = ({id}) => {
148148
Scheduler.log(id);
149+
React.useEffect(() => {
150+
Scheduler.log(`create effect ${id}`);
151+
return () => {
152+
Scheduler.log(`cleanup effect ${id}`);
153+
};
154+
});
149155
return id;
150156
};
151157

@@ -167,7 +173,20 @@ describe('ReactInternalTestUtils', () => {
167173
</React.StrictMode>
168174
);
169175
});
170-
assertLog(['A', 'B', 'C']);
176+
assertLog([
177+
'A',
178+
'B',
179+
'C',
180+
'create effect A',
181+
'create effect B',
182+
'create effect C',
183+
]);
184+
185+
await act(() => {
186+
root.render(null);
187+
});
188+
189+
assertLog(['cleanup effect A', 'cleanup effect B', 'cleanup effect C']);
171190
});
172191
});
173192

packages/react-reconciler/src/ReactFiberWorkLoop.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ import {
249249
markRenderStopped,
250250
onCommitRoot as onCommitRootDevTools,
251251
onPostCommitRoot as onPostCommitRootDevTools,
252+
setIsStrictModeForDevtools,
252253
} from './ReactFiberDevToolsHook';
253254
import {onCommitRoot as onCommitRootTestSelector} from './ReactTestSelectors';
254255
import {releaseCache} from './ReactFiberCacheComponent';
@@ -3667,6 +3668,7 @@ function doubleInvokeEffectsOnFiber(
36673668
fiber: Fiber,
36683669
shouldDoubleInvokePassiveEffects: boolean = true,
36693670
) {
3671+
setIsStrictModeForDevtools(true);
36703672
disappearLayoutEffects(fiber);
36713673
if (shouldDoubleInvokePassiveEffects) {
36723674
disconnectPassiveEffect(fiber);
@@ -3675,6 +3677,7 @@ function doubleInvokeEffectsOnFiber(
36753677
if (shouldDoubleInvokePassiveEffects) {
36763678
reconnectPassiveEffects(root, fiber, NoLanes, null, false);
36773679
}
3680+
setIsStrictModeForDevtools(false);
36783681
}
36793682

36803683
function doubleInvokeEffectsInDEVIfNecessary(

packages/react-reconciler/src/__tests__/ReactUpdaters-test.internal.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ describe('updaters', () => {
8181
markRenderScheduled: jest.fn(() => {}),
8282
markForceUpdateScheduled: jest.fn(() => {}),
8383
markStateUpdateScheduled: jest.fn(() => {}),
84+
setIsStrictModeForDevtools: jest.fn(() => {}),
8485
};
8586

8687
jest.mock(

packages/react-reconciler/src/__tests__/StrictEffectsModeDefaults-test.internal.js

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -115,11 +115,7 @@ describe('StrictEffectsMode defaults', () => {
115115
</React.StrictMode>,
116116
);
117117

118-
await waitForPaint([
119-
'useLayoutEffect mount "one"',
120-
'useLayoutEffect unmount "one"',
121-
'useLayoutEffect mount "one"',
122-
]);
118+
await waitForPaint(['useLayoutEffect mount "one"']);
123119
expect(log).toEqual([
124120
'useLayoutEffect mount "one"',
125121
'useLayoutEffect unmount "one"',
@@ -142,10 +138,6 @@ describe('StrictEffectsMode defaults', () => {
142138
'useLayoutEffect unmount "one"',
143139
'useLayoutEffect mount "one"',
144140
'useLayoutEffect mount "two"',
145-
146-
// Since "two" is new, it should be double-invoked.
147-
'useLayoutEffect unmount "two"',
148-
'useLayoutEffect mount "two"',
149141
]);
150142
expect(log).toEqual([
151143
// Cleanup and re-run "one" (and "two") since there is no dependencies array.
@@ -196,10 +188,6 @@ describe('StrictEffectsMode defaults', () => {
196188
await waitForAll([
197189
'useLayoutEffect mount "one"',
198190
'useEffect mount "one"',
199-
'useLayoutEffect unmount "one"',
200-
'useEffect unmount "one"',
201-
'useLayoutEffect mount "one"',
202-
'useEffect mount "one"',
203191
]);
204192
expect(log).toEqual([
205193
'useLayoutEffect mount "one"',
@@ -237,12 +225,6 @@ describe('StrictEffectsMode defaults', () => {
237225
'useEffect unmount "one"',
238226
'useEffect mount "one"',
239227
'useEffect mount "two"',
240-
241-
// Since "two" is new, it should be double-invoked.
242-
'useLayoutEffect unmount "two"',
243-
'useEffect unmount "two"',
244-
'useLayoutEffect mount "two"',
245-
'useEffect mount "two"',
246228
]);
247229
expect(log).toEqual([
248230
'useEffect unmount "one"',

packages/react/src/__tests__/ReactStrictMode-test.js

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1343,6 +1343,40 @@ describe('context legacy', () => {
13431343
// and on the next render they'd get deduplicated and ignored.
13441344
expect(console.log).toBeCalledWith('foo 1');
13451345
});
1346+
1347+
it('does not disable logs for effect double invoke', async () => {
1348+
let create = 0;
1349+
let cleanup = 0;
1350+
function Foo() {
1351+
React.useEffect(() => {
1352+
create++;
1353+
console.log('foo create ' + create);
1354+
return () => {
1355+
cleanup++;
1356+
console.log('foo cleanup ' + cleanup);
1357+
};
1358+
});
1359+
return null;
1360+
}
1361+
1362+
const container = document.createElement('div');
1363+
const root = ReactDOMClient.createRoot(container);
1364+
await act(() => {
1365+
root.render(
1366+
<React.StrictMode>
1367+
<Foo />
1368+
</React.StrictMode>,
1369+
);
1370+
});
1371+
expect(create).toBe(__DEV__ ? 2 : 1);
1372+
expect(cleanup).toBe(__DEV__ ? 1 : 0);
1373+
expect(console.log).toBeCalledTimes(__DEV__ ? 3 : 1);
1374+
// Note: we should display the first log because otherwise
1375+
// there is a risk of suppressing warnings when they happen,
1376+
// and on the next render they'd get deduplicated and ignored.
1377+
expect(console.log).toBeCalledWith('foo create 1');
1378+
expect(console.log).toBeCalledWith('foo cleanup 1');
1379+
});
13461380
} else {
13471381
it('disable logs for class double render', async () => {
13481382
let count = 0;
@@ -1530,6 +1564,40 @@ describe('context legacy', () => {
15301564
// and on the next render they'd get deduplicated and ignored.
15311565
expect(console.log).toBeCalledWith('foo 1');
15321566
});
1567+
1568+
it('disable logs for effect double invoke', async () => {
1569+
let create = 0;
1570+
let cleanup = 0;
1571+
function Foo() {
1572+
React.useEffect(() => {
1573+
create++;
1574+
console.log('foo create ' + create);
1575+
return () => {
1576+
cleanup++;
1577+
console.log('foo cleanup ' + cleanup);
1578+
};
1579+
});
1580+
return null;
1581+
}
1582+
1583+
const container = document.createElement('div');
1584+
const root = ReactDOMClient.createRoot(container);
1585+
await act(() => {
1586+
root.render(
1587+
<React.StrictMode>
1588+
<Foo />
1589+
</React.StrictMode>,
1590+
);
1591+
});
1592+
expect(create).toBe(__DEV__ ? 2 : 1);
1593+
expect(cleanup).toBe(__DEV__ ? 1 : 0);
1594+
expect(console.log).toBeCalledTimes(1);
1595+
// Note: we should display the first log because otherwise
1596+
// there is a risk of suppressing warnings when they happen,
1597+
// and on the next render they'd get deduplicated and ignored.
1598+
expect(console.log).toBeCalledWith('foo create 1');
1599+
expect(console.log).toBeCalledWith('foo cleanup 1');
1600+
});
15331601
}
15341602
});
15351603
});

0 commit comments

Comments
 (0)