You build a dashboard. It has an input box and a memoized list: <FilterList filters={filters} />. Every keystroke on the input re-renders the dashboard, and each render ALLOCATES a fresh filters literal — same fields, same values, new object. You memoized the child to skip that work. You type a character. The child re-renders. You type another. Re-renders. The memo did nothing.
FilterList · memo re-renders0Counter idle. Press the === button below to reproduce what a single keystroke does in the real dashboard.
The scale above holds two marbles. Left pan: an object with {sort:'date', tags:['urgent','review'], pageSize:25, filters:{…}}. Right pan: the SAME fields, same values, but constructed separately — a fresh heap pointer. Tap the === button on the fulcrum. Watch the scale tilt. Watch the memo counter climb. Every press is a keystroke in the real dashboard; every tick is a wasted re-render your memo was supposed to prevent.
=== answers ONE question: “is this the SAME pointer in memory?” For primitives that's fine — the number 42 always lives at the same spot. For objects it's almost never the question you wanted to ask. You wanted to ask “is this the SAME SHAPE?” — and no built-in operator does that for you. The scale cannot balance identical content because === isn't looking at content at all. It's looking at the mailing address, and the two marbles live at different addresses.