当前位置: 首页 > news >正文

在 Zustand 中创建通用 Action 的优雅实践

为何需要通用 Action?

在 Zustand 状态管理库中,开发者常常需要为状态对象的每个字段单独编写更新函数。然而,随着状态结构的复杂化,这种方式会导致代码冗余,维护成本增加。例如:

updateName: (name) => set(() => ({ name })),
updateAge: (age) => set(() => ({ age })),
updateEmail: (email) => set(() => ({ email })),
// 更多字段意味着更多重复代码

在类似 dva(类 Redux)框架中,通常通过定义一个通用 reducer 来简化状态更新操作:

export default {namespace: 'user',state: {name: '好人',age: 18,},reducers: {save(state, { payload }) {return { ...state, ...payload };},},
};
dispatch({ type: 'user/save', payload: { name: '更好的人' } });

那么,如何在 Zustand 中优雅地实现类似的功能?本文将介绍如何通过 TypeScript 泛型实现通用 Action,提升代码简洁性和可维护性。

通用 Action 的实现原理

通过 TypeScript 的泛型和 keyof 操作符,我们可以设计一个通用的更新函数,签名如下:

update: <K extends keyof State>(k: K, v: State[K]) => void;

该函数接受两个参数:

  1. k:状态对象的键名,类型为 keyof State,确保键名属于状态对象。
  2. v:对应键的新值,类型为 State[K],保证值与字段类型匹配。

这种设计不仅减少了重复代码,还提供了类型安全和自动补全支持。

完整实现方案

以下是实现通用 Action 的详细步骤:

1. 定义状态和 Action 类型

首先,定义状态和 Action 的类型,确保类型安全:

type State = {name: string;age: number;
};type Action = {update: <K extends keyof State>(k: K, v: State[K]) => void;updateName: (name: State['name']) => void;updateAge: (age: State['age']) => void;
};

2. 创建 Store 并实现通用 Action

在 Zustand 的 Store 中实现通用更新函数,并保留传统的单一字段更新函数以支持不同场景:

import { create } from 'zustand';type Store = State & { actions: Action };export const useStore = create<Store>()((set) => ({name: '',age: 18,actions: {updateName: (name) => set(() => ({ name })),updateAge: (age) => set(() => ({ age })),update: (k, v) => set(() => ({ [k]: v })),},
}));

3. 提取 Action 的便捷 Hook

为了方便在组件中调用 Action,创建一个 Hook 来提取 actions 对象:

export function useStoreActions() {return useStore((state) => state.actions);
}

使用场景对比

传统方式

传统方式需要为每个字段调用特定的更新函数:

const actions = useStoreActions();actions.updateName('Alice');
actions.updateAge(25);

通用 Action 方式

使用通用 update 函数,代码更加简洁统一:

const actions = useStoreActions();actions.update('name', 'Alice');
actions.update('age', 25);

确保类型安全

通用 update 函数通过 TypeScript 泛型提供了强大的类型安全支持,确保:

  • 只能更新状态中已定义的字段。
  • 传入的值必须与字段类型匹配。
  • 开发工具(如 VS Code)提供字段名的自动补全。

以下操作将触发类型错误:

actions.update('nonexistent', 'value'); // 错误:字段不存在
actions.update('age', '25'); // 错误:类型不匹配

扩展:支持批量更新

为了进一步提升灵活性,可以扩展通用 Action 以支持批量更新:

类型定义

type Action = {update: <K extends keyof State>(k: K, v: State[K]) => void;batchUpdate: (updates: Partial<State>) => void;updateName: (name: State['name']) => void;updateAge: (age: State['age']) => void;
};

实现批量更新

在 Store 中添加 batchUpdate 函数:

export const useStore = create<Store>()((set) => ({name: '',age: 18,actions: {updateName: (name) => set(() => ({ name })),updateAge: (age) => set(() => ({ age })),update: (k, v) => set(() => ({ [k]: v })),batchUpdate: (updates) => set((state) => ({ ...state, ...updates })),},
}));

使用批量更新

const actions = useStoreActions();actions.batchUpdate({ name: 'Bob', age: 30 });

总结

通过在 Zustand 中实现通用 Action,我们可以获得以下优势:

  1. 代码简洁:将所有更新逻辑统一到一个 update 函数,减少重复代码。
  2. 类型安全:利用 TypeScript 泛型和 keyof 操作符,确保字段和值的类型正确。
  3. 灵活扩展:支持批量更新,适应更复杂的业务场景。
  4. 清晰结构:将 Action 集中在一个对象中,避免与状态数据混淆,方便管理和调用。
http://www.wxhsa.cn/company.asp?id=2174

相关文章:

  • 如何用产品思维优化简历的“用户体验”?
  • 简历如何优化,简历如何投递,面试如何准备?
  • 网络流做题笔记
  • 简历优化全攻略:如何写出吸引HR的简历?
  • 重塑云上 AI 应用“运行时”,函数计算进化之路
  • 25.9.12 C语言基本数据类型
  • Avalonia:基础导航
  • bashrc的一些配置记录
  • H5游戏性能优化系列-----协议相关优化
  • 实现我的第一个langchain应用
  • 小说可视化系统设计(程序员副业项目)
  • MyEMS与开源浪潮:如何重塑全球能源管理的未来格局
  • React Antd or Antd Pro:findDOMNode is deprecated and will be removed in the next major release.
  • 单板挑战4路YOLOv8!米尔瑞芯微RK3576开发板性能实测
  • doms.ul.querySelectorvs document.querySelector:DOM查询的层级关系
  • 穿越钱塘江:一条高铁隧道背后的技术挑战
  • Pwn2Own Automotive 2025 决赛日:49个零日漏洞与88万美元奖金揭晓
  • 9.HPA与VPA
  • MyEMS在行动:揭秘开源能源管理系统如何重塑工业与楼宇的能效未来
  • 题解:P14015 [ICPC 2024 Nanjing R] 生日礼物
  • 吻得太逼真
  • HyperWorks许可回收机制
  • flink on k8s的基本介绍
  • 高性能计算基础
  • flutter开发window打包成exe可执行文件的步骤
  • Transtion动画组件要求包裹元素必须是单一根节点
  • linux启动ntp服务
  • 企业级 AI Agent 开发指南:基于函数计算 FC Sandbox 方案实现类 Chat Coding AI Agent
  • android开发局域网内通过NTP服务端自动更新系统时间
  • 一招解决Proxmox VE虚拟机磁盘空间耗尽:LVM在线扩容实战 - 若