Using zustand in react - performance gains (Pt. 1)

Let's try to make sure that when the user interacts with the header, the items won't render. For this we make use of the zustand hook overload that allows us to pass a selector into it:

export function HeaderDisplay() {
  const { title, changeHeader } = useAppStore(({ header, changeHeader }) => ({
    title: header.title,
  return (
    <header className={styles.header}>
      <label>This is the data header:</label>
        onChange={(e) => changeHeader(}

You can see in the first line the use of the selector. We only select the things that we really need. That should help, should it not?

When we check with the profile we will see that nothing has changed. Items keep rendering for naught.

Let's try this for selecting from the store:

const {
    header: { title },
  } = useAppStore(({ header, changeHeader }) => ({

The difference being that we select from the store's 1st level properties and deconstruct what we need outside of the store's selector. Any change?


(This one surprised me, I was under the impression that this works).

So, what exactly entails Zustand's promise that when you use selectors you can make sure only those parts of the app render that need re-rendering?

With this knowledge, we need to rewrite Header, Items and Item:




Once you run the profiler again, on my hardware I immediately notice that the snappiness of the app is as it should be when editing the header. And indeed, the profiler confirms what is happening.

Header still takes a minuscule amount to render, but the Item components are now completely passive

The items do not render anymore

In the next post we'll try and see whether we can avoid all 4'000 components from rerendering when we change the checkbox of a single item.

Editing a single item makes the Items component re-render

Toggling a single item still has a major impact
Creative Commons License

Frank Quednau 2022