Why is this memoized selector still causing extra renders?

Yoshiii
Tue, 07 Apr 2026 21:14:28 +0000

@BobaMilk yup, the main issue is activeId being in the useMemo deps even though the filter only depends on items.

So this part should just be:

js
const visible = useMemo(() => {
  return items.filter(item => item.visible);
}, [items]);

But that alone will not stop Sidebar from running when activeId changes. That rerender is expected, because every pass you recompute item.id === activeId, and at least the old active row and new active row get different active props.

If you want to cut the extra row work, the better boundary is usually Row:

js
const Row = React.memo(function Row({ item, active }) {
return {item.label} ;
});

That way, when activeId changes from 1 to 2, usually only those two rows need to update. One gotcha: if the parent recreates each item object every render, React.memo will not help much because the prop identity keeps changing.

Yoshiii