别再折磨自己了!放弃 Redux 后,我用 Zustand + TS 爽到起飞

前言:Redux 真的太难了...

作为一个刚入坑 React 不久的小白,我最近真的被状态管理搞得头皮发麻

跟着教程学 Redux,一会儿 Action,一会儿 Reducer,一会儿又是 Selector... 我只是想存个数字,却要写一堆模板代码,文件切来切去,人都绕晕了。直到昨天,我在社区看到大佬安利 Zustand,号称只有 1KB,而且不用包组件,不用写 Provider。

我不信邪试了一下... 哇!这也太香了吧!

它写起来就像原生 JS 一样简单粗暴,配合 TypeScript 的智能提示,简直是为我们这种"手残党"量身定做的!今天就迫不及待把我的学习笔记(源码)分享给大家,希望能帮到同样迷茫的小伙伴!


第一关:从最简单的计数器开始

以前用 Redux 写个计数器要建好几个文件,用 Zustand 居然只要一个函数就搞定?

TypeScript

typescript 复制代码
import { create } from 'zustand';

interface CounterState {
  count: number;
  increment: () => void;
  decrement: () => void;
  reset: () => void;
}

// create 后面接个泛型 <CounterState>,TS 马上就知道里面有什么
export const useCounterStore = create<CounterState>()((set, get) => ({
  // 状态直接列出来,清晰明了!
  n: 1, // 虽然接口里没定义这个,先放着(小声bb)
  count: 0,
  
  // 👇 这里我要自我检讨一下!
  // 为了省事我用了 any... 大佬们轻喷 
  // set((state: any) => ...) 
  // 其实是因为我刚学 TS,有时候类型报错搞不定就用 any 大法保平安
  // 大家千万别学我,后面我会改进的!
  increment: () => set((state: any) => ({ count: state.count + 1 })),
  
  decrement: () => set((state: any) => ({ count: state.count - 1 })),
  
  // 这种直接重置的写法太舒服了,不用深拷贝什么的
  reset: () => set({ count: 0 })
}));

小白心得

虽然代码里那一坨 any 有点辣眼睛,但你们看这个逻辑!没有 switch-case,没有 dispatch,就是简单的函数调用!这才是人类该写的代码啊!


第二关:Todo List + 持久化魔法

接下来的需求是做一个待办事项列表。这里我发现 Zustand 有个超级厉害的中间件叫 persist。

以前我要把数据存到 localStorage,得在 useEffect 里写好几行。现在?只要配置一行代码! 刷新页面数据居然真的还在,当时我就震惊了!😲

TypeScript

typescript 复制代码
import { create } from 'zustand';
import { persist } from 'zustand/middleware';

// 先定义清楚我们的 Todo 长什么样,TS 的好处体现出来了
export interface Todo {
    id: number,
    title: string,
    completed: boolean,
}

export interface TodoState {
    todos: Todo[],
    addTodo: (title: string) => void,
    removeTodo: (id: number) => void,
    toggleTodo: (id: number) => void,
}

// 这里的 <TodoState> 就像给代码装了导航仪
// 在写下面的 set 函数时,它会自动提示 todos 属性,太爽了
export const useTodoStore = create<TodoState>()(
  persist(
    (set, get) => ({
      todos: [],
      
      addTodo: (text: string) => 
        set((state) => ({
          // 这里的 ...state.todos 是不可变数据的写法
          // 虽然有点绕,但为了 React 能更新视图,我忍了!
          todos: [...state.todos, { 
            id: + Date.now(), 
            title: text,  
            completed: false,
          }]
        })),
        
      toggleTodo: (id: number) => 
        set((state) => ({
          todos: state.todos.map((todo) => 
            todo.id === id ? 
            {...todo, completed: !todo.completed} // 反转状态
            : todo
          )
        })),
        
      removeTodo: (id: number) => 
        set((state) => ({
          todos: state.todos.filter(todo => todo.id !== id)
        })),
    }),
    {
      name: 'todos', // 👇 见证奇迹的时刻!只要这一行,自动存 LocalStorage
    }
  )
)

真香时刻

只要加上 persist 和 { name: 'todos' },剩下的脏活累活 Zustand 全包了。这体验,简直是从原始社会直接跨入现代文明!🌆


第三关:用户登录 & 接口规范

最后是用户模块。以前写 JS 的时候,经常不知道 user 对象里到底有 username 还是 userName,拼错单词 debug 半天。

现在配合 TS 的 interface,把规矩立在前面:

TypeScript

typescript 复制代码
import { create } from 'zustand';
import { persist } from 'zustand/middleware'; 

// 定义用户长啥样
export interface User {
    id: number,
    username: string,
    avatar?: string, // ? 表示头像可有可无
}

interface UserState {
  isLoggin: boolean; // 虽然这里我想写 isLoggedIn,但不小心拼错了...
  login: (user: { username: string; password: string }) => void;
  logout: () => void; 
  user: User | null;
}

export const useUserStore = create<UserState>()(
  persist(
    (set) => ({
      isLoggin: false,
      // 登录逻辑简直到离谱,一行代码搞定状态切换
      login: (user) => set({ isLoggin: true, user: null }), 
      logut: () => set({ isLoggin: false, user: null }),
      user: null,
    }),
    {
      name: 'user',
    }
  )
)

TS 初体验总结

虽然定义 interface User 和 UserState 确实要多写几行代码,但在TRAE里写代码时,那种敲一个点 . 就能自动弹出属性的感觉,真的太有安全感了! 再也不怕因为手滑写错单词而报错了。


结尾碎碎念

作为一个前端萌新,我觉得 Zustand + TypeScript 简直是绝配!

  • Zustand 负责简单(拒绝样板代码)。
  • TypeScript 负责安全(拒绝低级错误)。

如果你也像我一样被 Redux 折磨得痛不欲生,赶紧去试试 Zustand 吧!入股不亏!


相关推荐
吴声子夜歌17 分钟前
ES6——Iterator和for...of循环详解
前端·javascript·es6
小李子呢021121 分钟前
前端八股3---ref和reactive
开发语言·前端·javascript
落魄江湖行25 分钟前
基础篇三 Nuxt4 组件进阶:插槽与事件传递
前端·nuxt4
kerli25 分钟前
Compose 组件:LazyColumn 核心参数与 key/contentType 详解
android·前端
好运的阿财26 分钟前
“锟斤拷”问题——程序中用powershell执行命令出现中文乱码的解决办法
linux·前端·人工智能·机器学习·架构·编辑器·vim
踩着两条虫37 分钟前
VTJ.PRO AI + 低代码实战:接入高德地图
前端·vue.js·ai编程
绝世唐门三哥38 分钟前
React性能优化:memo、useMemo和useCallback全解析
前端·react.js·memo
兔子零102440 分钟前
Claude Code 都把宠物养进终端了,我做了一个真正能长期玩的中文宠物游戏
前端·游戏·游戏开发
xiaotao13141 分钟前
Vite 与 Webpack 开发/打包时环境变量对比
前端·vue.js·webpack
摆烂工程师1 小时前
教你如何查询 Codex 最新额度是多少,以及 ChatGPT Pro、Plus、Business 最新额度变化
前端·后端·ai编程