This is very simple, but it doesn’t seem to come up when I search.
If you a have a component rendered with React.memo and are trying to figure out which prop is causing it to re-render:
export const Foo = React.memo((props: FooProps) => {
// ...
});
… you can (ab)use React.memo’s second parameter, propsAreEqual.
/**
* Lets you skip re-rendering a component when its props are unchanged.
*
* @param Component — The component to memoize.
* @param propsAreEqual — A function that will be used to determine if the props have changed.
*/
function React.memo<(props: ArticleCardProps) => React.JSX.Element>(
Component: (props: ArticleCardProps) => React.JSX.Element,
propsAreEqual?: ((prevProps: Readonly<ArticleCardProps>, nextProps: Readonly<...>) => boolean) | undefined
): React.MemoExoticComponent<...> (+1 overload)
The default propsAreEqual argument compares each prop with Object.is.
We’ll do the same but also log when a prop changes:
export const propsAreEqualWithLogging = <T>(prevProps: any, nextProps: any) => {
const keys = new Set([...Object.keys(prevProps), ...Object.keys(nextProps)]);
let out = true;
for (const key of keys) {
const equal = Object.is(prevProps[key as keyof T], nextProps[key as keyof T]);
if (!equal) {
console.log("Δ", key);
out = false;
}
}
return out;
};
export const Foo = React.memo((props: FooProps) => {
// ...
}, propsAreEqualWithLogging);
Now we’ll get log messages when a prop changes:
Δ bar
Easy!