Hint
This is the most common React.memo pitfall. Inline object/array literals in JSX (<List items={[1,2,3]} />) create new references every parent render, defeating memo.
function shallowEqual(a, b) {
return Object.keys(a).every(k => a[k] === b[k]) &&
Object.keys(b).every(k => b[k] === a[k]);
}
let renders = 0;
function memo(Component) {
let prev = null;
return (props) => {
if (prev && shallowEqual(prev, props)) { return 'skipped'; }
prev = props;
renders++;
return Component(props);
};
}
const List = ({ items }) => 'list:' + items.join(',');
const MemoList = memo(List);
const stableItems = [1, 2, 3]; // defined outside
console.log(MemoList({ items: stableItems })); // render
console.log(MemoList({ items: stableItems })); // skip — same ref
console.log(MemoList({ items: [1, 2, 3] })); // render — new array!
console.log(renders);list:1,2,3 skipped list:1,2,3 2
Explanation: stableItems is the same reference both times — skip. [1,2,3] literal creates a new array each call — different reference → re-renders despite same content.
Key Insight: This is the most common React.memo pitfall. Inline object/array literals in JSX () create new references every parent render, defeating memo.