更新 state
更新状态
扁平更新
用 Zustand 更新状态很简单!调用提供的 set 函数并传入新的状态,它将与存储中的现有状态浅层合并。注意:下一节将介绍嵌套状态。
import {create} from 'zustand'
type State = { firstName: string lastName: string}
type Action = { updateFirstName: (firstName: State ['firstName']) => void updateLastName: (lastName: State ['lastName']) => void}
// 创建你的存储,它包含状态和(可选的)动作const usePersonStore = create<State & Action>((set) => ({ firstName: '', lastName: '', updateFirstName: (firstName) => set (() => ({ firstName: firstName })), updateLastName: (lastName) => set (() => ({ lastName: lastName })),}))
// 在消费应用中function App () { // "选择" 需要的状态和动作,在这个例子中,是 firstName 的值和动作 updateFirstName const firstName = usePersonStore ((state) => state.firstName) const updateFirstName = usePersonStore ((state) => state.updateFirstName)
return ( <main> <label> First name <input // 更新 "firstName" 状态 onChange={(e) => updateFirstName (e.currentTarget.value)} value={firstName} /> </label>
<p> Hello, <strong>{firstName}!</strong> </p> </main> )}
深度嵌套对象
如果你有一个像这样的深度状态对象:
type State = { deep: { nested: { obj: { count: number } } }}
更新嵌套状态需要一些努力,以确保过程是不可变的。
常规方法
与 React 或 Redux 类似,常规方法是复制状态对象的每一层。这是通过扩展运算符… 完成的,并手动将其与新的状态值合并。像这样:
normalInc: () => set ((state) => ({ deep: { ...state.deep, nested: { ...state.deep.nested, obj: { ...state.deep.nested.obj, count: state.deep.nested.obj.count + 1 } } } })),
这很长!让我们探索一些可以让你的生活更轻松的替代方案。
使用 Immer
许多人使用 Immer 来更新嵌套值。你可以在需要更新嵌套状态的任何时候使用 Immer,比如在 React、Redux 和当然,Zustand 中!
你可以使用 Immer 来缩短你的深度嵌套对象的状态更新。让我们看一个例子:
immerInc: () => set (produce ((state: State) => { ++state.deep.nested.obj.count })),
这个缩减幅度很大!请注意这里列出的注意事项。
使用 optics-ts
还有另一个使用 optics-ts 的选项:
opticsInc: () => set (O.modify (O.optic<State>().path ("deep.nested.obj.count"))((c) => c + 1)),
与 Immer 不同,optics-ts 不使用代理或变异语法。
使用 Ramda
你也可以使用 Ramda:
ramdaInc: () => set (R.modifyPath (["deep", "nested", "obj", "count"], (c) => c + 1)),
ramda 和 optics-ts 也可以和类型一起工作。
CodeSandbox 演示
https://codesandbox.io/s/zustand-normal-immer-optics-ramda-updating-ynn3o?file=/src/App.tsx