Passing a new object as a prop defeats memo

memo compares props by reference, so an inline object, array or function is a new value on every render and the memo never hits.

// memo does nothing: style and onSelect are new each time
<Row style={{ padding: 8 }} onSelect={() => pick(row.id)} />

// hoisted, and stable
const ROW_STYLE = { padding: 8 }
const onSelect = useCallback((id) => pick(id), [pick])

<Row style={ROW_STYLE} onSelect={onSelect} row={row} />

Passing the id to a stable handler rather than closing over it per row is the pattern that scales, because a useCallback per row is not a stable reference either. This is also why memoising is so often measured as having no effect: the component is memoised, the props are not, and nothing about the code says so.