diff --git a/packages/react-devtools-shared/src/__tests__/console-test.js b/packages/react-devtools-shared/src/__tests__/console-test.js index e2674b10f3526..e8f5376c7bf2e 100644 --- a/packages/react-devtools-shared/src/__tests__/console-test.js +++ b/packages/react-devtools-shared/src/__tests__/console-test.js @@ -625,6 +625,147 @@ describe('console', () => { expect(mockGroupCollapsed.mock.calls[0][0]).toBe('groupCollapsed'); }); + it('should double log from useMemo if hideConsoleLogsInStrictMode is disabled in Strict mode', () => { + global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = false; + global.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = false; + + const container = document.createElement('div'); + const root = ReactDOMClient.createRoot(container); + + function App() { + React.useMemo(() => { + fakeConsole.log('log'); + fakeConsole.warn('warn'); + fakeConsole.error('error'); + fakeConsole.info('info'); + fakeConsole.group('group'); + fakeConsole.groupCollapsed('groupCollapsed'); + }, []); + return
; + } + + act(() => + root.render( + + + , + ), + ); + expect(mockLog.mock.calls[0]).toHaveLength(1); + expect(mockLog.mock.calls[0][0]).toBe('log'); + expect(mockLog.mock.calls[1]).toEqual([ + '%c%s', + `color: ${process.env.DARK_MODE_DIMMED_LOG_COLOR}`, + 'log', + ]); + + expect(mockWarn).toHaveBeenCalledTimes(2); + expect(mockWarn.mock.calls[0]).toHaveLength(1); + expect(mockWarn.mock.calls[0][0]).toBe('warn'); + expect(mockWarn.mock.calls[1]).toHaveLength(3); + expect(mockWarn.mock.calls[1]).toEqual([ + '%c%s', + `color: ${process.env.DARK_MODE_DIMMED_WARNING_COLOR}`, + 'warn', + ]); + + expect(mockError).toHaveBeenCalledTimes(2); + expect(mockError.mock.calls[0]).toHaveLength(1); + expect(mockError.mock.calls[0][0]).toBe('error'); + expect(mockError.mock.calls[1]).toHaveLength(3); + expect(mockError.mock.calls[1]).toEqual([ + '%c%s', + `color: ${process.env.DARK_MODE_DIMMED_ERROR_COLOR}`, + 'error', + ]); + + expect(mockInfo).toHaveBeenCalledTimes(2); + expect(mockInfo.mock.calls[0]).toHaveLength(1); + expect(mockInfo.mock.calls[0][0]).toBe('info'); + expect(mockInfo.mock.calls[1]).toHaveLength(3); + expect(mockInfo.mock.calls[1]).toEqual([ + '%c%s', + `color: ${process.env.DARK_MODE_DIMMED_LOG_COLOR}`, + 'info', + ]); + + expect(mockGroup).toHaveBeenCalledTimes(2); + expect(mockGroup.mock.calls[0]).toHaveLength(1); + expect(mockGroup.mock.calls[0][0]).toBe('group'); + expect(mockGroup.mock.calls[1]).toHaveLength(3); + expect(mockGroup.mock.calls[1]).toEqual([ + '%c%s', + `color: ${process.env.DARK_MODE_DIMMED_LOG_COLOR}`, + 'group', + ]); + + expect(mockGroupCollapsed).toHaveBeenCalledTimes(2); + expect(mockGroupCollapsed.mock.calls[0]).toHaveLength(1); + expect(mockGroupCollapsed.mock.calls[0][0]).toBe('groupCollapsed'); + expect(mockGroupCollapsed.mock.calls[1]).toHaveLength(3); + expect(mockGroupCollapsed.mock.calls[1]).toEqual([ + '%c%s', + `color: ${process.env.DARK_MODE_DIMMED_LOG_COLOR}`, + 'groupCollapsed', + ]); + }); + + it('should not double log from useMemo fns if hideConsoleLogsInStrictMode is enabled in Strict mode', () => { + global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = false; + global.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = true; + + const container = document.createElement('div'); + const root = ReactDOMClient.createRoot(container); + + function App() { + React.useMemo(() => { + console.log( + 'CALL', + global.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__, + ); + fakeConsole.log('log'); + fakeConsole.warn('warn'); + fakeConsole.error('error'); + fakeConsole.info('info'); + fakeConsole.group('group'); + fakeConsole.groupCollapsed('groupCollapsed'); + }, []); + return
; + } + + act(() => + root.render( + + + , + ), + ); + + expect(mockLog).toHaveBeenCalledTimes(1); + expect(mockLog.mock.calls[0]).toHaveLength(1); + expect(mockLog.mock.calls[0][0]).toBe('log'); + + expect(mockWarn).toHaveBeenCalledTimes(1); + expect(mockWarn.mock.calls[0]).toHaveLength(1); + expect(mockWarn.mock.calls[0][0]).toBe('warn'); + + expect(mockError).toHaveBeenCalledTimes(1); + expect(mockError.mock.calls[0]).toHaveLength(1); + expect(mockError.mock.calls[0][0]).toBe('error'); + + expect(mockInfo).toHaveBeenCalledTimes(1); + expect(mockInfo.mock.calls[0]).toHaveLength(1); + expect(mockInfo.mock.calls[0][0]).toBe('info'); + + expect(mockGroup).toHaveBeenCalledTimes(1); + expect(mockGroup.mock.calls[0]).toHaveLength(1); + expect(mockGroup.mock.calls[0][0]).toBe('group'); + + expect(mockGroupCollapsed).toHaveBeenCalledTimes(1); + expect(mockGroupCollapsed.mock.calls[0]).toHaveLength(1); + expect(mockGroupCollapsed.mock.calls[0][0]).toBe('groupCollapsed'); + }); + it('should double log in Strict mode initial render for extension', () => { global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = false; global.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = false; diff --git a/packages/react-reconciler/src/ReactFiberHooks.js b/packages/react-reconciler/src/ReactFiberHooks.js index e6a9f14a03969..edd572542c04e 100644 --- a/packages/react-reconciler/src/ReactFiberHooks.js +++ b/packages/react-reconciler/src/ReactFiberHooks.js @@ -2636,10 +2636,12 @@ function mountMemo( ): T { const hook = mountWorkInProgressHook(); const nextDeps = deps === undefined ? null : deps; + const nextValue = nextCreate(); if (shouldDoubleInvokeUserFnsInHooksDEV) { + setIsStrictModeForDevtools(true); nextCreate(); + setIsStrictModeForDevtools(false); } - const nextValue = nextCreate(); hook.memoizedState = [nextValue, nextDeps]; return nextValue; } @@ -2658,10 +2660,12 @@ function updateMemo( return prevState[0]; } } + const nextValue = nextCreate(); if (shouldDoubleInvokeUserFnsInHooksDEV) { + setIsStrictModeForDevtools(true); nextCreate(); + setIsStrictModeForDevtools(false); } - const nextValue = nextCreate(); hook.memoizedState = [nextValue, nextDeps]; return nextValue; }