Skip to content

useShallow ⚛️

useShallow 是一个 React Hook,可让你优化重新渲染。

¥useShallow is a React Hook that lets you optimize re-renders.

js
const memoizedSelector = useShallow(selector)

签名

¥Signature

ts
useShallow<T, U = T>(selectorFn: (state: T) => U): (state: T) => U

参考

¥Reference

useShallow(selectorFn)

参数

¥Parameters

  • selectorFn:允许你返回基于当前状态的数据的函数。

    ¥selectorFn: A function that lets you return data that is based on current state.

返回

¥Returns

useShallow 返回使用浅比较进行记忆的选择器函数的记忆版本。

¥useShallow returns a memoized version of a selector function using a shallow comparison for memoization.

用法

¥Usage

编写记忆选择器

¥Writing a memoized selector

首先,我们需要设置一个存储来保存熊家族的状态。在此存储中,我们定义了三个属性:papaBearmamaBearbabyBear,分别代表熊家族的不同成员及其各自的燕麦罐尺寸。

¥First, we need to setup a store to hold the state for the bear family. In this store, we define three properties: papaBear, mamaBear, and babyBear, each representing a different member of the bear family and their respective oatmeal pot sizes.

tsx
import { create } from 'zustand'

type BearFamilyMealsStore = {
  [key: string]: string
}

const useBearFamilyMealsStore = create<BearFamilyMealsStore>()(() => ({
  papaBear: 'large porridge-pot',
  mamaBear: 'middle-size porridge pot',
  babyBear: 'A little, small, wee pot',
}))

接下来,我们将创建一个 BearNames 组件,它检索我们状态(熊家庭成员)的键并显示它们。

¥Next, we'll create a BearNames component that retrieves the keys of our state (the bear family members) and displays them.

tsx
function BearNames() {
  const names = useBearFamilyMealsStore((state) => Object.keys(state))

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

接下来,我们将创建一个 UpdateBabyBearMeal 组件,定期更新小熊的膳食选择。

¥Next, we will create a UpdateBabyBearMeal component that periodically updates baby bear's meal choice.

tsx
const meals = [
  'A tiny, little, wee bowl',
  'A small, petite, tiny pot',
  'A wee, itty-bitty, small bowl',
  'A little, petite, tiny dish',
  'A tiny, small, wee vessel',
  'A small, little, wee cauldron',
  'A little, tiny, small cup',
  'A wee, small, little jar',
  'A tiny, wee, small pan',
  'A small, wee, little crock',
]

function UpdateBabyBearMeal() {
  useEffect(() => {
    const timer = setInterval(() => {
      useBearFamilyMealsStore.setState({
        tinyBear: meals[Math.floor(Math.random() * (meals.length - 1))],
      })
    }, 1000)

    return () => {
      clearInterval(timer)
    }
  }, [])

  return null
}

最后,我们将 App 组件中的两个组件组合起来,看看它们的实际效果。

¥Finally, we combine both components in the App component to see them in action.

tsx
export default function App() {
  return (
    <>
      <UpdateTinyBearPorridge />
      <BearNames />
    </>
  )
}

代码应该是这样的:

¥Here is what the code should look like:

tsx
import { useEffect } from 'react'
import { create } from 'zustand'

type BearFamilyMealsStore = {
  [key: string]: string
}

const useBearFamilyMealsStore = create<BearFamilyMealsStore>()(() => ({
  papaBear: 'large porridge-pot',
  mamaBear: 'middle-size porridge pot',
  babyBear: 'A little, small, wee pot',
}))

const meals = [
  'A tiny, little, wee bowl',
  'A small, petite, tiny pot',
  'A wee, itty-bitty, small bowl',
  'A little, petite, tiny dish',
  'A tiny, small, wee vessel',
  'A small, little, wee cauldron',
  'A little, tiny, small cup',
  'A wee, small, little jar',
  'A tiny, wee, small pan',
  'A small, wee, little crock',
]

function UpdateBabyBearMeal() {
  useEffect(() => {
    const timer = setInterval(() => {
      useBearFamilyMealsStore.setState({
        tinyBear: meals[Math.floor(Math.random() * (meals.length - 1))],
      })
    }, 1000)

    return () => {
      clearInterval(timer)
    }
  }, [])

  return null
}

function BearNames() {
  const names = useBearFamilyMealsStore((state) => Object.keys(state))

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

export default function App() {
  return (
    <>
      <UpdateBabyBearMeal />
      <BearNames />
    </>
  )
}

一切看起来都很好,但有一个小问题:即使名称没有改变,BearNames 组件也会不断重新渲染。发生这种情况的原因是,只要状态的任何部分发生变化,组件就会重新渲染,即使我们关心的特定部分(名称列表)没有改变。

¥Everything might look fine, but there’s a small problem: the BearNames component keeps re-rendering even if the names haven’t changed. This happens because the component re-renders whenever any part of the state changes, even if the specific part we care about (the list of names) hasn’t changed.

要修复此问题,我们使用 useShallow 来确保组件仅在状态的实际键发生变化时重新渲染:

¥To fix this, we use useShallow to make sure the component only re-renders when the actual keys of the state change:

tsx
function BearNames() {
  const names = useBearFamilyStore(useShallow((state) => Object.keys(state)))

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

代码应该是这样的:

¥Here is what the code should look like:

tsx
import { useEffect } from 'react'
import { create } from 'zustand'
import { useShallow } from 'zustand/react/shallow'

type BearFamilyMealsStore = {
  [key: string]: string
}

const useBearFamilyMealsStore = create<BearFamilyMealsStore>()(() => ({
  papaBear: 'large porridge-pot',
  mamaBear: 'middle-size porridge pot',
  babyBear: 'A little, small, wee pot',
}))

const meals = [
  'A tiny, little, wee bowl',
  'A small, petite, tiny pot',
  'A wee, itty-bitty, small bowl',
  'A little, petite, tiny dish',
  'A tiny, small, wee vessel',
  'A small, little, wee cauldron',
  'A little, tiny, small cup',
  'A wee, small, little jar',
  'A tiny, wee, small pan',
  'A small, wee, little crock',
]

function UpdateBabyBearMeal() {
  useEffect(() => {
    const timer = setInterval(() => {
      useBearFamilyMealsStore.setState({
        tinyBear: meals[Math.floor(Math.random() * (meals.length - 1))],
      })
    }, 1000)

    return () => {
      clearInterval(timer)
    }
  }, [])

  return null
}

function BearNames() {
  const names = useBearFamilyMealsStore(
    useShallow((state) => Object.keys(state)),
  )

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

export default function App() {
  return (
    <>
      <UpdateBabyBearMeal />
      <BearNames />
    </>
  )
}

通过使用 useShallow,我们优化了渲染过程,确保组件仅在必要时重新渲染,从而提高整体性能。

¥By using useShallow, we optimized the rendering process, ensuring that the component only re-renders when necessary, which improves overall performance.

故障排除

¥Troubleshooting

TBD

Zustand v5.0 中文网 - 粤ICP备13048890号