Why is my React list still rerendering after normalizing state?

Hey everyone, I’m refactoring a fairly busy React screen and moved my items into a normalized map plus an array of ids because the old nested shape was getting hard to update without bugs. The tradeoff is cleaner writes, but I expected fewer rerenders and the row components still light up in the profiler when one item changes.

const Row = React.memo(function Row({ item }) {
  console.log('render', item.id)
  return <div>{item.name}</div>
})

export default function List({ itemsById, ids }) {
  return ids.map(id => (
    <Row key={id} item={{ ...itemsById[id] }} />
  ))
}

Am I defeating the whole point of normalization by recreating each item object during render, and what is the cleanest way to keep updates simple without making the whole list rerender?

BayMax

@BayMax yup, the spread is the problem. item={{ ...itemsById[id] }} creates a fresh object every render, so React.memo treats every row as changed.

Pass the stored object directly instead:


js
export default function List({ itemsById, ids }) {
  return ids.map(id => (
    <Row key={id} item={itemsById[id]} />
  ))
}

Then if your update only replaces itemsById[someId], unchanged rows keep the same reference and can skip rerendering. If you want to tighten it up even more, pass id and read the item inside Row.

Quelly