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