Zustand基础入门 - react状态管理

100 阅读2分钟

引言

最近公司需求较少,去B站跟着一位学习了一下,主要是对一些代码加了自己理解的注释,有需要的直接看注释吧

store.js

import { create } from 'zustand'
import { createJSONStorage, devtools, persist, subscribeWithSelector } from 'zustand/middleware'
import { immer } from 'zustand/middleware/immer'
devtools
interface AppleStore {
  price: number
  count: number
  color: string
  addCount: () => void
  decrement: () => void
  getTotal: () => number
  doubleCount: () => Promise<undefined>
}

const useAppleStore = create<AppleStore>()(
  // 同步修改中间件
  immer(
    // 使用redux调试
    devtools(
      // 订阅细化中间件
      subscribeWithSelector(
        // 持久化存储中间件
        persist(
          // 状态回调
          (set, get) => ({
            price: 10,
            count: 5,
            color: 'red',
            // 增加数量
            addCount: () => {
              set((state) => {
                state.count += 1
              })
            },
            // 常规修改
            // addCount:()=>{
            //   set((state)=>({count: state.count + 1}))
            // },
            // 减少数量
            decrement: () => {
              set((state) => {
                state.count -= 1
              })
            },
            getTotal: () => {
              return get().price * get().count
            },
            async doubleCount() {
              const rate = await Promise.resolve(2)
              set((state) => {
                state.count *= rate
              })
            },
          }),
          {
            name: 'myAppleStore',
            // 持久化选择一条数据
            // partialize:(state) => ({price:state.price})
            // 持久化筛出某一条price
            // Object.fromEntries -- 二维数组转对象 [[aa:'bb']] => {aa:'bb'}
            // Object.entries -- 对象转二维数组 {aa:'bb'} => [[aa:'bb']]
            partialize: (state) => Object.fromEntries(Object.entries(state).filter(([key]) => !['price'].includes(key))),
            // 存入sessionStorage还是localStorage
            storage: createJSONStorage(() => sessionStorage),
          }
        )
      ),
      { enabled: true, name: 'apple Store' }
    )
  )
)

export default useAppleStore


// 单独封装store修改方法 --- 原作者推荐
export const addCount = () => {
  useAppleStore.setState((state) => {
    state.count += 1
  })
}  

export const decrement = () => {
  useAppleStore.setState((state) => {
    state.count -= 1
  })
}

export const getTotal = () => {
  return useAppleStore.getState().price * useAppleStore.getState().count
}

export const doubleCount = async () => {
    const rate = await Promise.resolve(2)
    useAppleStore.setState((state) => {
      state.count *= rate
    })
}

App.tsx

import { Fragment, useEffect, useState } from 'react'
import './App.css'
import useAppleStore, { addCount, decrement, doubleCount, getTotal } from './store/appleStore'
import { useShallow } from 'zustand/react/shallow'
import { shallow } from 'zustand/shallow'

const Child1 = () => {
  // 取值方法1
  const price = useAppleStore((state) => state.price)
  const count = useAppleStore((state) => state.count)
  // const addCount = useAppleStore((state) => state.addCount)
  // const decrement = useAppleStore((state) => state.decrement)
  // const getTotal = useAppleStore((state) => state.getTotal)
  // const doubleCount = useAppleStore((state) => state.doubleCount)

  /**
   * 组件修改store状态
   */
  const myLocalAction = () => {
    // 修改数据
    useAppleStore.setState((state) => ({
      ...state,
      price: state.price + 10
    }))
    // 拿取数据
    console.log(useAppleStore.getState().price)
  }
  
  return (
    <Fragment>
      <h1>价格:{price}</h1>
      <h1>数量:{count}</h1>
      <h1>总量:{getTotal()}</h1>
      <button onClick={addCount}>+1</button>
      <button onClick={decrement}>-1</button>
      <button onClick={doubleCount}>* 2 </button>
      <button onClick={myLocalAction}>独有状态+10</button>
    </Fragment>
  )
}

const Child2 = () => {

  const [text, setText] = useState('太少')

  // 取值方法2 -- 推荐
  const {color, price} = useAppleStore(useShallow(state => ({
    color: state.color,
    price: state.price,
  })))

  useEffect(() => {
    // 订阅,减少组件重新渲染 -- 监听所有state
    // const cancelSub = useAppleStore.subscribe((state, prevState) => {
    //   if(state.count >= 7 && prevState.count < 7){
    //     console.log(state.count)
    //     setText('太多了')
    //   } else if(state.count < 7 && prevState.count >= 7){
    //     setText('太少')
    //   }
    // })

    // 单一监听state中的count,需要搭配subscribeWithSelector
    const cancelSub = useAppleStore.subscribe(state => state.count, (count, prevCount) => {
      console.log(count)
      if(count >= 7 && (prevCount < 7 || count === prevCount)){
        setText('太多了')
      } else if(count < 7 && (prevCount >= 7 || count === prevCount)){
        setText('太少')
      }
    },
    {
      equalityFn: shallow,
      // 首次立即执行
      fireImmediately:true
    },
    )


    return cancelSub
  }, [])

  console.log('child2 ---- ')

  return (
    <>
      <h1>价格:{price}</h1>
      <h1>颜色:{color}</h1>
      <h1>{text}</h1>
    </>
  )
}

function App() {
  const [count, setCount] = useState(0)

  return (
    <>
     <Child1/>
     <Child2/>
    </>
  )
}

export default App