diff --git a/src/hooks/useSelector.ts b/src/hooks/useSelector.ts index c0363b4a5..53be410d6 100644 --- a/src/hooks/useSelector.ts +++ b/src/hooks/useSelector.ts @@ -99,6 +99,12 @@ export function createSelectorHook(context = ReactReduxContext): UseSelector { ) { const toCompare = selector(state) if (!equalityFn(selected, toCompare)) { + let stack: string | undefined = undefined + try { + throw new Error() + } catch (e) { + ;({ stack } = e as Error) + } console.warn( 'Selector ' + (selector.name || 'unknown') + @@ -108,6 +114,7 @@ export function createSelectorHook(context = ReactReduxContext): UseSelector { state, selected, selected2: toCompare, + stack, } ) } @@ -120,11 +127,18 @@ export function createSelectorHook(context = ReactReduxContext): UseSelector { ) { // @ts-ignore if (selected === state) { + let stack: string | undefined = undefined + try { + throw new Error() + } catch (e) { + ;({ stack } = e as Error) + } console.warn( 'Selector ' + (selector.name || 'unknown') + ' returned the root state when called. This can lead to unnecessary rerenders.' + - '\nSelectors that return the entire state are almost certainly a mistake, as they will cause a rerender whenever *anything* in state changes.' + '\nSelectors that return the entire state are almost certainly a mistake, as they will cause a rerender whenever *anything* in state changes.', + { stack } ) } } diff --git a/test/hooks/useSelector.spec.tsx b/test/hooks/useSelector.spec.tsx index ae38a10bb..4da35efb8 100644 --- a/test/hooks/useSelector.spec.tsx +++ b/test/hooks/useSelector.spec.tsx @@ -805,6 +805,7 @@ describe('React', () => { }), selected: expect.any(Number), selected2: expect.any(Number), + stack: expect.any(String), }) ) }) @@ -920,7 +921,10 @@ describe('React', () => { ) expect(consoleSpy).toHaveBeenCalledWith( - expect.stringContaining('returned the root state when called.') + expect.stringContaining('returned the root state when called.'), + expect.objectContaining({ + stack: expect.any(String), + }) ) }) })