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.