zustand/docs/guides/prevent-rerenders-with-use-shallow.md
Fabrizio Vitale 3cbd468fe5
feat: add useShallow (#2090)
* feat: add useShallow

See
- https://github.com/pmndrs/zustand/discussions/1937
- https://github.com/pmndrs/zustand/discussions/1937#discussioncomment-7118242
- https://github.com/pmndrs/zustand/discussions/1937#discussioncomment-6974554

* chore(useShallow): improve unit tests

* chore(useShallow): PR feedback https://github.com/pmndrs/zustand/pull/2090#discussion_r1341963105

* fix(useShallow): tests not working on test_matrix (cjs, production, CI-MATRIX-NOSKIP)

* chore(useShallow): fix eslint warning issue (unused import)

* refactor(useShallow): simplify tests

* docs(useShallow): add guide

* fix(useShallow): prettier:ci error https://github.com/pmndrs/zustand/actions/runs/6369420511/job/17289749161?pr=2090

* docs(useShallow): update readme

* docs(useShallow): remove obsolete line from readme

Co-authored-by: Daishi Kato <dai-shi@users.noreply.github.com>

* doc(useShallow): PR feedback https://github.com/pmndrs/zustand/pull/2090#discussion_r1342120701

* docs(useShallow): small improvements of the useShallow guide

---------

Co-authored-by: Daishi Kato <dai-shi@users.noreply.github.com>
2023-10-02 22:13:13 +09:00

1.6 KiB

title nav
Prevent rerenders with useShallow 16

When you need to subscribe to a computed state from a store, the recommended way is to use a selector.

The computed selector will cause a rererender if the output has changed according to Object.is.

In this case you might want to use useShallow to avoid a rerender if the computed value is always shallow equal the previous one.

Example

We have a store that associates to each bear a meal and we want to render their names.

import { create } from 'zustand'

const useMeals = create(() => ({
  papaBear: 'large porridge-pot',
  mamaBear: 'middle-size porridge pot',
  littleBear: 'A little, small, wee pot',
}))

export const BearNames = () => {
  const names = useMeals((state) => Object.keys(state))

  return <div>{names.join(', ')}</div>
}

Now papa bear wants a pizza instead:

useMeals.setState({
  papaBear: 'a large pizza',
})

This change causes BearNames rerenders even tho the actual output of names has not changed according to shallow equal.

We can fix that using useShallow!

import { create } from 'zustand'
import { useShallow } from 'zustand/shallow'

const useMeals = create(() => ({
  papaBear: 'large porridge-pot',
  mamaBear: 'middle-size porridge pot',
  littleBear: 'A little, small, wee pot',
}))

export const BearNames = () => {
  const names = useMeals(useShallow((state) => Object.keys(state)))

  return <div>{names.join(', ')}</div>
}

Now they can all order other meals without causing unnecessary rerenders of our BearNames component.