Skip to content

Commit b89c439

Browse files
committed
Current behavior of console calls during second invocation of Effects in Strict Mode
1 parent c25640b commit b89c439

3 files changed

Lines changed: 234 additions & 1 deletion

File tree

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

Lines changed: 26 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,26 @@ 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+
'cleanup effect A',
184+
'cleanup effect B',
185+
'cleanup effect C',
186+
'create effect A',
187+
'create effect B',
188+
'create effect C',
189+
]);
190+
191+
await act(() => {
192+
root.render(null);
193+
});
194+
195+
assertLog(['cleanup effect A', 'cleanup effect B', 'cleanup effect C']);
171196
});
172197
});
173198

packages/react-devtools-shared/src/__tests__/console-test.js

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,142 @@ describe('console', () => {
625625
expect(mockGroupCollapsed.mock.calls[0][0]).toBe('groupCollapsed');
626626
});
627627

628+
it('should double log from Effects if hideConsoleLogsInStrictMode is disabled in Strict mode', () => {
629+
global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = false;
630+
global.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = false;
631+
632+
const container = document.createElement('div');
633+
const root = ReactDOMClient.createRoot(container);
634+
635+
function App() {
636+
React.useEffect(() => {
637+
fakeConsole.log('log effect create');
638+
fakeConsole.warn('warn effect create');
639+
fakeConsole.error('error effect create');
640+
fakeConsole.info('info effect create');
641+
fakeConsole.group('group effect create');
642+
fakeConsole.groupCollapsed('groupCollapsed effect create');
643+
644+
return () => {
645+
fakeConsole.log('log effect cleanup');
646+
fakeConsole.warn('warn effect cleanup');
647+
fakeConsole.error('error effect cleanup');
648+
fakeConsole.info('info effect cleanup');
649+
fakeConsole.group('group effect cleanup');
650+
fakeConsole.groupCollapsed('groupCollapsed effect cleanup');
651+
};
652+
});
653+
654+
return <div />;
655+
}
656+
657+
act(() =>
658+
root.render(
659+
<React.StrictMode>
660+
<App />
661+
</React.StrictMode>,
662+
),
663+
);
664+
expect(mockLog.mock.calls).toEqual([
665+
['log effect create'],
666+
['log effect cleanup'],
667+
['log effect create'],
668+
]);
669+
expect(mockWarn.mock.calls).toEqual([
670+
['warn effect create'],
671+
['warn effect cleanup'],
672+
['warn effect create'],
673+
]);
674+
expect(mockError.mock.calls).toEqual([
675+
['error effect create'],
676+
['error effect cleanup'],
677+
['error effect create'],
678+
]);
679+
expect(mockInfo.mock.calls).toEqual([
680+
['info effect create'],
681+
['info effect cleanup'],
682+
['info effect create'],
683+
]);
684+
expect(mockGroup.mock.calls).toEqual([
685+
['group effect create'],
686+
['group effect cleanup'],
687+
['group effect create'],
688+
]);
689+
expect(mockGroupCollapsed.mock.calls).toEqual([
690+
['groupCollapsed effect create'],
691+
['groupCollapsed effect cleanup'],
692+
['groupCollapsed effect create'],
693+
]);
694+
});
695+
696+
it('should not double log from Effects if hideConsoleLogsInStrictMode is enabled in Strict mode', () => {
697+
global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = false;
698+
global.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = true;
699+
700+
const container = document.createElement('div');
701+
const root = ReactDOMClient.createRoot(container);
702+
703+
function App() {
704+
React.useEffect(() => {
705+
fakeConsole.log('log effect create');
706+
fakeConsole.warn('warn effect create');
707+
fakeConsole.error('error effect create');
708+
fakeConsole.info('info effect create');
709+
fakeConsole.group('group effect create');
710+
fakeConsole.groupCollapsed('groupCollapsed effect create');
711+
712+
return () => {
713+
fakeConsole.log('log effect cleanup');
714+
fakeConsole.warn('warn effect cleanup');
715+
fakeConsole.error('error effect cleanup');
716+
fakeConsole.info('info effect cleanup');
717+
fakeConsole.group('group effect cleanup');
718+
fakeConsole.groupCollapsed('groupCollapsed effect cleanup');
719+
};
720+
});
721+
722+
return <div />;
723+
}
724+
725+
act(() =>
726+
root.render(
727+
<React.StrictMode>
728+
<App />
729+
</React.StrictMode>,
730+
),
731+
);
732+
expect(mockLog.mock.calls).toEqual([
733+
['log effect create'],
734+
['log effect cleanup'],
735+
['log effect create'],
736+
]);
737+
expect(mockWarn.mock.calls).toEqual([
738+
['warn effect create'],
739+
['warn effect cleanup'],
740+
['warn effect create'],
741+
]);
742+
expect(mockError.mock.calls).toEqual([
743+
['error effect create'],
744+
['error effect cleanup'],
745+
['error effect create'],
746+
]);
747+
expect(mockInfo.mock.calls).toEqual([
748+
['info effect create'],
749+
['info effect cleanup'],
750+
['info effect create'],
751+
]);
752+
expect(mockGroup.mock.calls).toEqual([
753+
['group effect create'],
754+
['group effect cleanup'],
755+
['group effect create'],
756+
]);
757+
expect(mockGroupCollapsed.mock.calls).toEqual([
758+
['groupCollapsed effect create'],
759+
['groupCollapsed effect cleanup'],
760+
['groupCollapsed effect create'],
761+
]);
762+
});
763+
628764
it('should double log from useMemo if hideConsoleLogsInStrictMode is disabled in Strict mode', () => {
629765
global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = false;
630766
global.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = false;

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

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1343,6 +1343,42 @@ 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+
if (__DEV__) {
1379+
expect(console.log).toBeCalledWith('foo cleanup 1');
1380+
}
1381+
});
13461382
} else {
13471383
it('disable logs for class double render', async () => {
13481384
let count = 0;
@@ -1530,6 +1566,42 @@ describe('context legacy', () => {
15301566
// and on the next render they'd get deduplicated and ignored.
15311567
expect(console.log).toBeCalledWith('foo 1');
15321568
});
1569+
1570+
it('does not disable logs for effect double invoke', async () => {
1571+
let create = 0;
1572+
let cleanup = 0;
1573+
function Foo() {
1574+
React.useEffect(() => {
1575+
create++;
1576+
console.log('foo create ' + create);
1577+
return () => {
1578+
cleanup++;
1579+
console.log('foo cleanup ' + cleanup);
1580+
};
1581+
});
1582+
return null;
1583+
}
1584+
1585+
const container = document.createElement('div');
1586+
const root = ReactDOMClient.createRoot(container);
1587+
await act(() => {
1588+
root.render(
1589+
<React.StrictMode>
1590+
<Foo />
1591+
</React.StrictMode>,
1592+
);
1593+
});
1594+
expect(create).toBe(__DEV__ ? 2 : 1);
1595+
expect(cleanup).toBe(__DEV__ ? 1 : 0);
1596+
expect(console.log).toBeCalledTimes(__DEV__ ? 3 : 1);
1597+
// Note: we should display the first log because otherwise
1598+
// there is a risk of suppressing warnings when they happen,
1599+
// and on the next render they'd get deduplicated and ignored.
1600+
expect(console.log).toBeCalledWith('foo create 1');
1601+
if (__DEV__) {
1602+
expect(console.log).toBeCalledWith('foo cleanup 1');
1603+
}
1604+
});
15331605
}
15341606
});
15351607
});

0 commit comments

Comments
 (0)