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
- 在 react hook 组件中函数体内部使用全局的 state,需要使用
getState()方法获取,否则获取的是初始化的 state 值。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 })React 状态管理套件比较与原理实现 feat. Redux, Zustand, Jotai, Recoil, MobX, Valtio
