Last active
December 21, 2023 21:28
-
-
Save karimsa/8a7cf759ceb15f853ed9cfe15fb6aead to your computer and use it in GitHub Desktop.
debug react component renders
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable n/no-process-env */ | |
import { useCallback, useEffect, useRef } from "react"; | |
function useChangedValues(values: Record<string, unknown>) { | |
const valueStore = useRef(new Map()).current; | |
const changedKeys: string[] = []; | |
for (const [key, val] of Object.entries(values)) { | |
if (valueStore.get(key) !== val) { | |
changedKeys.push(key); | |
} | |
valueStore.set(key, val); | |
} | |
return changedKeys; | |
} | |
/** | |
* Identify when hook or props values change. The react profiler only | |
* figures out what props changed and it can't introspect the values. | |
* This hook is useful for debugging nested value changes. | |
* @param {String} name the name of your component | |
* @param {Object} object an object containing all your hook values to watch | |
*/ | |
function _debugComponentChanges( | |
fnId: string, | |
propValues: Record<string, unknown>, | |
hookValues: Record<string, unknown> | |
) { | |
const log = useCallback( | |
(msg: string) => console.log(`[${fnId}] ${msg}`), | |
[fnId] | |
); | |
// Track mount/unmount | |
useEffect(() => { | |
log("mounted"); | |
return () => log("unmounted"); | |
}, [log]); | |
const isFirstRenderRef = useRef(true); | |
const isFirstRender = isFirstRenderRef.current; | |
isFirstRenderRef.current = false; | |
const changedPropKeys = useChangedValues(propValues); | |
if (!isFirstRender && changedPropKeys.length > 0) { | |
log( | |
`props changed:\n${changedPropKeys.map((key) => ` - ${key}`).join("\n")}` | |
); | |
} | |
const changedHookKeys = useChangedValues(hookValues); | |
if (!isFirstRender && changedHookKeys.length > 0) { | |
log( | |
`hooks changed:\n${changedHookKeys.map((key) => ` - ${key}`).join("\n")}` | |
); | |
} | |
if ( | |
!isFirstRender && | |
changedPropKeys.length === 0 && | |
changedHookKeys.length === 0 | |
) { | |
console.log(`${fnId} rendered without changes`); | |
} | |
} | |
export const debugComponentChanges = | |
process.env.NODE_ENV === "development" ? _debugComponentChanges : () => null; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment