别再折磨自己了!放弃 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 吧!入股不亏!


相关推荐
donecoding1 小时前
Sass 模块化革命:告别 @import,拥抱 @use 和 @forward
前端·css·代码规范
m0_748252381 小时前
Angular 2 数据显示方法
前端·javascript·angular.js
2501_944711432 小时前
现代 React 路由实践指南
前端·react.js·前端框架
by————组态2 小时前
睿控(Ricon)组态
运维·前端·物联网·信息可视化·组态·组态软件
蓁蓁啊2 小时前
GCC 头文件搜索路径:-I vs -idirafter 深度解析
java·前端·javascript·嵌入式硬件·物联网
依赖_赖2 小时前
前端实现token无感刷新
前端·javascript·vue.js
RubyZhang2 小时前
小程序Canvas动态海报生成方案及性能优化报告
前端
zhelingwang2 小时前
设计模式笔记
前端
Focus_2 小时前
如何借助AI在UE5中将图片批量生成3D模型
前端·aigc·游戏开发