本文是《React管理平台》第八节
通过本文我们将学会如何在
zustand
中使用Immer
来简化复杂状态更新。
快速安装zustand
首先,我们需要通过以下命令安装zustand
依赖:
shell
# npm
npm i zustand
# pnpm
pnpm i zustand
# yarn
yarn add zustand
安装成功后,将在项目中看到如下依赖提示:
创建store
目录和相关文件
在store
目录下,创建user.ts
和index.ts
文件。
index.ts
的代码只需将useUserStore
从user.ts
中导出即可:
tsx
export { useUserStore } from './user'
设定用户状态存储 - user.ts
在user.ts
文件中,我们构建用户状态管理的核心代码:
tsx
// 引入zustand创建方法
import { create } from 'zustand'
// 用户信息类型定义
type UserInfo = {
username: string
avatar: string
}
// 动作类型定义
type Action = {
updateToken: (token: string) => void
updateUserInfo: (userInfo: UserInfo) => void
}
// 状态接口定义
interface State {
token: string
userInfo: UserInfo
}
// 创建zustand存储
export const useUserStore = create<State & Action>(set => ({
token: '',
userInfo: { username: '', avatar: '' },
updateToken: token => set({ token: token }),
updateUserInfo: userInfo => set({ userInfo: userInfo })
}))
详解user.ts
核心功能
步骤一:导入 create
方法
首先,我们从zustand
库中导入了create
方法。
tsx
import { create } from 'zustand'
步骤二:定义状态和动作类型
接着,我们定义了两种类型:UserInfo
和 Action
。
UserInfo
类型用于描述用户的基本信息。包含username
和avatar
两个字符串。Action
类型有updateToken
和updateUserInfo
两个更新函数。
tsx
type UserInfo = {
username: string
avatar: string
}
type Action = {
updateToken: (token: string) => void
updateUserInfo: (userInfo: UserInfo) => void
}
步骤三:设定状态接口
之后,我们定义了 State
的接口,以此表示存储中将会有哪些状态。
State
接口中有token
和userInfo
两个属性,分别用于存储用户的认证令牌和用户信息。
tsx
interface State {
token: string
userInfo: UserInfo
}
步骤四:创建 Zustand 存储
使用 create
方法和 Zustand 存储函数来创建存储。
create
方法接收一个设置函数(setter),该函数定义了存储的初始化状态以及如何更新这些状态。- 存储的初始状态中,
token
是空字符串,userInfo
也是包含空字符串的对象。
tsx
export const useUserStore = create<State & Action>(set => ({
token: '',
userInfo: { username: '', avatar: '' },
// ...
}))
步骤五:实现更新动作
在此存储函数中,我们定义了两个状态更新函数 updateToken
和 updateUserInfo
。
updateToken
函数接受token
参数,并使用set
方法更新存储中的token
值。updateUserInfo
函数接受userInfo
对象作为参数,并同样使用set
来更新存储中的userInfo
。
tsx
export const useUserStore = create<State & Action>(set => ({
// ...
updateToken: token =>
set({
token: token
}),
updateUserInfo: userInfo =>
set({
userInfo: userInfo
})
}))
步骤六:使用 useUserStore
钩子 最后,我们将创建的存储导出为 useUserStore
钩子。这样,在组件中就可以通过调用这个钩子来访问和更新状态了。
在 zustand
中使用 Immer
首先,在项目中安装immer
依赖:
shell
# npm
npm i immer
# pnpm
pnpm i immer
# yarn
yarn add immer
安装完成后,依赖包会出现在项目中,如下图所示:
使用Immer
中间件优化zustand
存储
使用Immer
中间件,使我们的状态更新代码更加直观和易于管理。
我们只需要使用 immer
包裹住之前的设置函数(setter)即可,以下是集成Immer
后的zustand
代码:
tsx
// 引入zustand库和Immer中间件
import { create } from 'zustand'
import { immer } from 'zustand/middleware/immer'
type UserInfo = {
username: string
avatar: string
}
type Action = {
updateToken: (token: string) => void
updateUserInfo?: (userInfo: UserInfo) => void
updateUserName: (username: string) => void
}
interface State {
token: string
userInfo: UserInfo
}
// 创建带有Immer中间件的zustand存储
export const useUserStore = create<State & Action>()(
// 这里使用了immer进行包裹住"设置函数"(setter)
immer(set => ({
token: '',
userInfo: { username: '', avatar: 'http://xxxx.com/yy.jpg' },
updateToken: token => set(state => { state.token = token }),
updateUserName: username => set(state => { state.userInfo.username = username })
}))
)
Immer
的工作原理及对比
使用Immer
可以愉快地更新不可变状态(immutable state)------我们不再需要使用...
展开运算符手动复制对象。Immer
提供了简化的API来更新深层嵌套的数据。
例如,通过Immer
进行状态更新时:
tsx
updateUserName: username => set(state => { state.userInfo.username = username })
而传统的不使用Immer
的代码需要使用拓展运算符来保留所有既有状态,并手动指定更改:
tsx
updateUserName: username =>
set(state => ({
...state, // 再次使用展开运算符复制所有既有状态
userInfo: {
...state.userInfo, // 复制 userInfo 对象内的其他属性
username: username // 只更新 username 属性
}
}))
效果展示
如下动图展示了使用Immer
更新状态的响应效果:
我们来对比不使用 immer
的代码,会发现很难维护:
tsx
export const useUserStore = create<State & Action>(set => ({
token: '',
userInfo: { username: '', avatar: 'http://xxxx.com/yy.jpg' },
updateToken: token =>
set(state => ({
...state, // 使用展开运算符复制所有既有状态
token: token // 更新 token 值
})),
updateUserName: username =>
set(state => ({
...state, // 再次使用展开运算符复制所有既有状态
userInfo: {
...state.userInfo, // 复制 userInfo 对象内的其他属性
username: username // 只更新 username 属性
}
}))
}))
总结
通过本文,我们对如何在zustand
中使用Immer
来简化复杂状态更新有了深入的了解。