Skip to content

Instantly share code, notes, and snippets.

@karimsa
Last active December 21, 2023 21:28
Show Gist options
  • Save karimsa/8a7cf759ceb15f853ed9cfe15fb6aead to your computer and use it in GitHub Desktop.
Save karimsa/8a7cf759ceb15f853ed9cfe15fb6aead to your computer and use it in GitHub Desktop.
debug react component renders
/* 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