Skip to content

React Store

redux toolkit

zustand

基本使用

定义Store

ts
// src/store/user.js

import { create } from 'zustand'

const initData = {
  userInfo: {},
  token: '',
}

export const useUserStore = create((set, get) => ({
  ...initData,
  setUserInfo: (userInfo) => set({ userInfo }),
  getUsername: () => {
    return get().userInfo?.username
  }
}))

在组件中使用

tsx
import {useUserStore} from '@/store/user.js'
import axios from "axios";

const Component = () => {
  const {token, setUserInfo, getUsername} = useUserStore()
  const userInfo = useUserStore((state)=>state.userInfo)

  const fetchUser = async () => {
    const state = useUserStore.getState()
    const { data } = await axios({
      url: '/xxx',
      headers: {
        'access-token': state.token,
      }
    })
    setUserInfo(data)
  }

  return (
      <div>
        用户:{getUsername()}
      </div>
  )
}

export default Component
  1. react hook 组件中函数体内部使用全局的 state,需要使用 getState() 方法获取,否则获取的是初始化的 state 值。
  2. zustand 的 state 是响应式的,所以可以直接在 jsx ui 中使用解构的 state 值 ,但是在非 jsx 中需要使用 getState() 方法获取最新状态。

跨组件数据共享、数据监听操作

数据监听需要使用 subscribeWithSelector 包裹,否则不能细粒度监听。

js
const unsub1 = useDogStore.subscribe(console.log)

1, 定义store

ts
// src/store/dialog.js

import { create } from 'zustand'
import { subscribeWithSelector } from 'zustand/middleware'

const initData = {
  newDialogVisible: false,
  newFormData: null,
}

export const useDialogStore = create(
  subscribeWithSelector((set, get) => ({
    ...initData,
    changeNewDialog(visible, data = null) {
      set({ newDialogVisible: visible, newFormData: data })
    },
  }))
)

2,设置数据

tsx
import { forwardRef, useImperativeHandle, useState } from 'react'
import { Button, Form } from 'antd'
import { useDialogStore } from '@/store/dialog.js'

const Dialog = (props, ref) => {
  useImperativeHandle(ref, () => ({
    showModal,
  }))
  const [form] = Form.useForm()
  const { changeNewDialog } = useDialogStore()

  const showModal = (data) => {
    changeNewDialog(true, {})
  }

  return (
      <>
        <Button onClick={showModal} htmlType="submit">新建</Button>
      </>
  )
}

export default forwardRef(Dialog)

3,监听数据变化

tsx
import { Breadcrumb } from 'antd'
import Side from './components/Side.jsx'
import List from './components/List.jsx'
import NewDialog from './components/NewDialog.jsx'
import { useEffect, useRef } from 'react'
import { useDialogStore } from '@/store/dialog.js'
import { shallow } from 'zustand/shallow'

const Page = () => {
  const newDialogRef = useRef()
  useEffect(() => {
    // 监听数据变化
    const unsub = useDialogStore.subscribe(
      (state) => [state.newDialogVisible, state.newFormData],
      ([visible, data]) => {
        if (visible) {
          // console.log(visible, data)
          newDialogRef.current.showModal(data)
        }
      },
      { equalityFn: shallow } // 浅比较
    )
    return () => {
      // 取消订阅
      unsub()
    }
  }, [])
  return (
    <>
      <Breadcrumb
        items={[
          {
            title: '首页',
          },
          {
            title: <a href="/">列表</a>,
          },
        ]}
      />
      <div className="border-b-[1px] border-solid border-gray-300 ml-[-20px] mr-[-20px] mt-[15px]"></div>
      <div className="flex justify-between">
        <Side />
        <List />
      </div>
      <NewDialog ref={newDialogRef} />
    </>
  )
}

export default Page

TSX之外使用

ts
// react 组件外直接取值
const token = useUserStore.getState().token
// react 组件外更新值
useUserStore.setState({ userInfo: data })

zustand 搞定 react 中复杂状态管理

React 状态管理套件比较与原理实现 feat. Redux, Zustand, Jotai, Recoil, MobX, Valtio

Zustand 和 React Context