Skip to main content

useWhyDidYouUpdate

Description and use case​

useWhyDidYouUpdate deeply compares a component's incoming props against the previous render's props and reports exactly which keys changed. Every change is classified: a real value change, or a [Reference Changed Only] wasted render caused by a brand-new object/array/function literal that carries the same data.

Reach for it when a component re-renders more than expected and you need to find the specific prop causing it, especially unstable inline objects, arrays, or callbacks passed from a parent.

API signature​

function useWhyDidYouUpdate(
name: string,
props: Record<string, unknown>,
options?: UseWhyDidYouUpdateOptions,
): WhyDidYouUpdateChange[];

Parameters​

NameTypeRequiredDescription
namestringYesDisplay name used in log messages.
propsRecord<string, unknown>YesThe current render's props to diff.
optionsUseWhyDidYouUpdateOptionsNoLogging and comparison controls (see below).

Options​

NameTypeDefaultDescription
enabledbooleantrueEnable/disable in development. Always a noop returning [] in production builds (NODE_ENV === 'production'), regardless of this option, so bundlers can eliminate the deep-equality/logging logic entirely.
logType'console' | 'object''console''console' logs changes via console.group; 'object' stays silent.
deepCheckbooleanfalseStructurally compare changed values to detect reference-only churn.
maxDepthnumber10Max recursion depth for deepCheck, guarding against deep or circular structures.

Return value​

An array of WhyDidYouUpdateChange, one per changed key (empty on the first render or when nothing changed):

FieldTypeDescription
keystringThe prop key that changed.
previousValueunknownValue on the previous render.
currentValueunknownValue on the current render.
referenceChangedOnlybooleantrue when deepCheck found the data structurally identical.

Code example​

import { useWhyDidYouUpdate } from 'react-perf-hooks';

function HeavyList(props: { items: Item[]; onSelect: (id: string) => void }) {
useWhyDidYouUpdate('HeavyList', props, { deepCheck: true });

return (
<ul>
{props.items.map((item) => (
<li key={item.id} onClick={() => props.onSelect(item.id)}>
{item.label}
</li>
))}
</ul>
);
}

Companion article​