WinddSnow

Zustand-Lightweight-State-Management-Create-Store-Async-Actions-Middleware

字数统计: 5.3k阅读时长: 22 min
2026/08/01

第101课:Zustand 轻量状态管理——创建 Store、异步 action、中间件、与 Redux 对比

Redux Toolkit 提供了强大且完整的状态管理方案,但它的概念体系(Store、Reducer、Action、Dispatch、Middleware)和样板代码仍然有一定的学习成本。Zustand(德语“状态”)是一个极简、基于 Hook 的轻量状态管理库,它的核心理念是:状态就是一个普通的 JavaScript 对象,修改状态的函数就定义在这个对象旁边。无需 Provider 包裹、无需 action type 常量、无需 dispatch——你直接调用修改函数即可。Zustand 的 API 表面积极小,但足以覆盖绝大多数应用场景,包括异步 action中间件(如持久化、DevTools)、选择器优化TypeScript 泛型。本节课将从零开始,深入 Zustand 的 Store 创建、状态读取与修改、异步操作处理、中间件集成,并最终与 Redux Toolkit 进行公平对比,帮助你在两者之间做出明智的技术选型。


1. Zustand 的核心哲学与安装

Zustand 由 React Spring 和 Jotai 的作者开发,设计目标是在保持 React 函数式编程模型的同时,提供极简的全局状态管理。它的特点包括:

  • 无需 Provider:Store 是一个独立于组件树的 JavaScript 模块,直接通过自定义 Hook 访问,不需要在根组件包裹任何 Context Provider。
  • 无样板代码:创建 Store 只需一个 create 函数,状态和修改函数定义在同一个对象中。
  • 基于不可变更新:内部使用 Object.is 进行变化检测,与 React 的渲染优化兼容。
  • 支持选择器:组件可以选择性地订阅 Store 中的某一部分数据,仅在所选数据变化时重新渲染。
  • 支持中间件:内置 persist(持久化)、devtools(Redux DevTools 集成)、immer(Immer 不可变更新)等中间件。

1.1 安装

1
npm install zustand

Zustand 的核心包体积极小(约 1KB gzipped),且没有任何外部依赖。如果在 TypeScript 项目中使用,类型定义已内置,无需额外安装 @types


2. 创建 Store 与基本读写

2.1 create 函数

Zustand 通过 create 函数创建一个 Store。create 接收一个回调函数,该回调接收 setget 作为参数,返回一个包含状态修改函数的对象。create 的返回值是一个自定义 Hook。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// store.js
import { create } from 'zustand';

const useCounterStore = create((set) => ({
// 状态
count: 0,

// 修改函数
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
reset: () => set({ count: 0 }),
}));

export default useCounterStore;

关键解析

  • set 是一个函数,用于合并更新 Store 中的状态。它接收一个对象(部分状态)或一个回调函数(接收当前 state,返回部分状态对象)。与 React 的 setState 类似,set 只更新你传入的字段,其他字段保持不变。
  • get 是另一个可选参数,它返回当前的完整状态。在不需要响应式更新、仅想读取最新值的场景中使用 get(),例如在异步回调中获取最新状态而不重新渲染组件。
  • create 返回的 useCounterStore 是一个 Hook,可以在任何 React 组件中调用。

2.2 在组件中读取状态

在组件中调用 Store Hook(如 useCounterStore),并传入一个选择器函数来提取所需的状态片段。组件仅在选择器返回的值变化时重新渲染。

1
2
3
4
5
6
7
// CounterDisplay.jsx
import useCounterStore from './store';

function CounterDisplay() {
const count = useCounterStore((state) => state.count);
return <p>计数:{count}</p>;
}

如果你需要多个状态字段,可以调用多次 Hook,每次用选择器提取一个基本值。也可以一次返回一个对象,但需要注意——如果返回一个新对象,每次 Store 更新都会触发重新渲染(因为对象引用每次不同)。解决方案是使用 shallow 比较函数。

1
2
3
4
5
6
7
8
9
import { useShallow } from 'zustand/shallow';

// 使用 useShallow 安全地返回多个字段
function CounterInfo() {
const { count, max } = useCounterStore(
useShallow((state) => ({ count: state.count, max: state.max }))
);
return <p>{count} / {max}</p>;
}

2.3 在组件中修改状态

修改函数本身也是 Store 的一部分,通过选择器获取它们即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// CounterControls.jsx
import useCounterStore from './store';

function CounterControls() {
const increment = useCounterStore((state) => state.increment);
const decrement = useCounterStore((state) => state.decrement);
const reset = useCounterStore((state) => state.reset);

return (
<div>
<button onClick={increment}>+1</button>
<button onClick={decrement}>-1</button>
<button onClick={reset}>重置</button>
</div>
);
}

注意:修改函数(如 increment)的引用是稳定的——它们在 Store 创建时就已确定,不会在每次渲染时变化。这意味着即使不用 useCallback 包裹,将它们传递给 React.memo 子组件也不会导致不必要的渲染。

2.4 在组件外部访问 Store

Zustand 的 Store 不仅是 React Hook——它还是一个普通的 JavaScript 模块。你可以通过 useCounterStore.getState() 在任何地方(包括非 React 代码、事件处理、异步回调)读取当前状态,通过 useCounterStore.setState() 修改状态。这完全绕过了 React 的渲染周期。

1
2
3
4
5
6
7
8
9
10
11
12
// 在普通 JavaScript 文件中读取和修改
import useCounterStore from './store';

console.log(useCounterStore.getState().count); // 获取当前值

useCounterStore.setState({ count: 100 }); // 直接设置

// 订阅状态变化(不触发 React 渲染)
const unsubscribe = useCounterStore.subscribe((state) => {
console.log('新状态:', state);
});
// 取消订阅: unsubscribe()

这种“脱离组件树”的能力使得 Zustand 非常适合处理非 UI 逻辑——如 WebSocket 消息处理、定时器、第三方 SDK 集成等——这些逻辑可以放在普通的 TypeScript 文件中,通过 getStatesetState 与 Store 交互,无需通过 React 组件间接访问。


3. 异步 Action

在 Zustand 中,异步操作不需要特殊的中间件。你可以在 create 回调中直接定义一个 async 函数作为修改函数,在其中使用 set 更新状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// store.js
import { create } from 'zustand';

const useUserStore = create((set, get) => ({
user: null,
loading: false,
error: null,

fetchUser: async (userId) => {
set({ loading: true, error: null });
try {
const res = await fetch(`/api/users/${userId}`);
if (!res.ok) throw new Error('请求失败');
const user = await res.json();
set({ user, loading: false });
} catch (err) {
set({ error: err.message, loading: false });
}
},

clearUser: () => set({ user: null, error: null }),
}));

export default useUserStore;

关键行为

  • 异步函数中,set 可以多次调用(分别更新 loadingusererror),每次调用都会通知订阅者。这符合直觉,无需像 Redux 那样 dispatch 多个 action。
  • get 可以在异步回调中读取最新状态。例如,在 fetchUser 中,可以在请求前通过 get().user 判断是否已有缓存,避免重复请求。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 组件中使用
function UserProfile({ userId }) {
const { user, loading, error, fetchUser } = useUserStore(
useShallow((state) => ({
user: state.user,
loading: state.loading,
error: state.error,
fetchUser: state.fetchUser,
}))
);

useEffect(() => {
fetchUser(userId);
}, [userId, fetchUser]);

if (loading) return <div>加载中...</div>;
if (error) return <div>错误:{error}</div>;
if (!user) return null;

return <h2>{user.name}</h2>;
}

与 Redux 异步对比

  • Zustand:直接写 async 函数,内部调用 set。没有 action type、没有 thunk、没有 extraReducers
  • Redux Toolkit:使用 createAsyncThunk 定义 thunk,在 extraReducers 中手动处理 pending/fulfilled/rejected。更结构化,但代码量更多。

4. 中间件

Zustand 的 Store 可以通过中间件增强。中间件是一个高阶函数,包裹原始的 create 函数。Zustand 内置了三个最常用的中间件。

4.1 persist:持久化到 localStorage

persist 中间件自动将 Store 中的数据同步到 localStorage(或 sessionStorageAsyncStorage),并在页面刷新后恢复。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { create } from 'zustand';
import { persist } from 'zustand/middleware';

const useThemeStore = create(
persist(
(set) => ({
theme: 'light',
toggleTheme: () =>
set((state) => ({ theme: state.theme === 'light' ? 'dark' : 'light' })),
}),
{
name: 'theme-storage', // localStorage 中的 key
// 可选:只持久化部分字段
partialize: (state) => ({ theme: state.theme }),
}
)
);

关键配置

  • name:存储在 localStorage 中的键名,必须唯一,避免不同 Store 的持久化数据冲突。
  • partialize:一个函数,接收完整状态,返回需要持久化的子对象。用于过滤掉不需要持久化的字段(如临时状态、loadingerror)。
  • version:可选版本号。当 Store 数据结构发生变化时,递增版本号可触发迁移逻辑。
  • migrate:可选迁移函数,接收旧版本持久化数据和版本号,返回新版本的状态。

4.2 devtools:集成 Redux DevTools

devtools 中间件将 Zustand Store 连接到 Redux DevTools 浏览器扩展,允许你查看状态变化的时间线、手动跳转和调试。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import { create } from 'zustand';
import { devtools } from 'zustand/middleware';

const useTaskStore = create(
devtools(
(set) => ({
tasks: [],
addTask: (text) =>
set(
(state) => ({ tasks: [...state.tasks, { id: Date.now(), text }] }),
false, // 第二个参数:是否替换整个 state(false = 合并)
'addTask' // 第三个参数:在 DevTools 中显示的 action 名称
),
removeTask: (id) =>
set(
(state) => ({ tasks: state.tasks.filter((t) => t.id !== id) }),
false,
'removeTask'
),
}),
{ name: 'TaskStore' } // DevTools 中显示的 Store 名称
)
);

set 在 DevTools 模式下的三个参数

  1. 部分状态对象或更新函数。
  2. replace:如果为 true,完全替换当前状态(而非合并)。默认 false
  3. actionName:在 DevTools 中为这次更新显示的名称。强烈建议为每个 set 调用提供有意义的 action 名称,否则 DevTools 中会显示 anonymous,无法区分不同操作。

4.3 immer:简化不可变更新

如果你更喜欢 Redux Toolkit 中 Immer 的“可变”语法,Zustand 也提供了 immer 中间件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import { create } from 'zustand';
import { immer } from 'zustand/middleware/immer';

const useCartStore = create(
immer((set) => ({
items: [],
addItem: (product) =>
set((state) => {
const existing = state.items.find((item) => item.id === product.id);
if (existing) {
existing.quantity += 1; // 直接修改(Immer 转为不可变)
} else {
state.items.push({ ...product, quantity: 1 });
}
}),
removeItem: (id) =>
set((state) => {
state.items = state.items.filter((item) => item.id !== id);
}),
}))
);

4.4 组合多个中间件

Zustand 中间件可以通过函数组合的方式嵌套使用。中间件的应用顺序是从内到外(与函数组合一致):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { create } from 'zustand';
import { persist, devtools, immer } from 'zustand/middleware';

const useStore = create(
devtools(
persist(
immer((set) => ({
// ... 状态和修改函数
})),
{ name: 'my-store' }
),
{ name: 'MyStore' }
)
);

从内到外:immerpersistdevtools。每个中间件包裹下一个中间件增强后的 create 回调。


5. Zustand 与 Redux Toolkit 对比

维度 Zustand Redux Toolkit
概念复杂度 极少:Store、setget 较多:Store、Reducer、Action、Dispatch、Thunk
API 表面积 极小,核心仅 create 中等,configureStorecreateSlicecreateAsyncThunk
模板代码量 几乎为零 有(Slice 定义、Store 配置、Provider)
异步处理 直接写 async 函数,内部调用 set 使用 createAsyncThunk,手动处理生命周期
缓存/数据获取 需自行封装或使用第三方库(TanStack Query) RTK Query 内置,声明式 API 端点
TypeScript 类型推导极佳,几乎无需手动标注 类型推导良好,需少量样板(RootStateAppDispatch
DevTools 通过 devtools 中间件支持 开箱即支持
中间件生态 内置 persistdevtoolsimmer 极其丰富(redux-saga、redux-observable 等)
适用场景 中小型应用、偏好简洁 API、非 React 环境 大型应用、团队协作、需要 RTK Query
包体积 ~1KB gzipped ~11KB gzipped(含 RTK Query)

选型建议

  • 优先 Zustand:中小型项目、新项目探索阶段、偏好极简 API、需要频繁在组件外访问 Store(WebSocket、定时器)。
  • 优先 Redux Toolkit:大型团队协作(标准化 reducer 模式利于 Code Review)、需要 RTK Query 的缓存方案、需要中间件生态(如 redux-saga)、与遗留 Redux 代码共存。
  • 两者可以共存:例如,使用 Zustand 管理 UI 状态(如主题、模态框开关),使用 RTK Query 管理服务端数据缓存。

6. 综合实战:全局购物车与用户认证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// store.js
import { create } from 'zustand';
import { persist, devtools } from 'zustand/middleware';

const useStore = create(
devtools(
persist(
(set, get) => ({
// ---- 用户状态 ----
user: null,
isAuthenticated: false,

login: async (username, password) => {
set({ loading: true }, false, 'auth/loginStart');
try {
const res = await fetch('/api/login', {
method: 'POST',
body: JSON.stringify({ username, password }),
});
if (!res.ok) throw new Error('登录失败');
const user = await res.json();
set({ user, isAuthenticated: true, loading: false }, false, 'auth/loginSuccess');
} catch (err) {
set({ error: err.message, loading: false }, false, 'auth/loginFailure');
}
},

logout: () => {
set({ user: null, isAuthenticated: false }, false, 'auth/logout');
},

// ---- 购物车状态 ----
cart: [],
addToCart: (product) =>
set(
(state) => {
const existing = state.cart.find((item) => item.id === product.id);
if (existing) {
return {
cart: state.cart.map((item) =>
item.id === product.id ? { ...item, quantity: item.quantity + 1 } : item
),
};
}
return { cart: [...state.cart, { ...product, quantity: 1 }] };
},
false,
'cart/addItem'
),
removeFromCart: (id) =>
set(
(state) => ({ cart: state.cart.filter((item) => item.id !== id) }),
false,
'cart/removeItem'
),
clearCart: () => set({ cart: [] }, false, 'cart/clear'),

// ---- 通用状态 ----
loading: false,
error: null,
}),
{
name: 'app-store',
partialize: (state) => ({
user: state.user,
isAuthenticated: state.isAuthenticated,
cart: state.cart,
}), // 仅持久化用户和购物车,不持久化 loading/error
}
),
{ name: 'AppStore' }
)
);

export default useStore;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// App.jsx
import useStore from './store';
import { useShallow } from 'zustand/shallow';

function LoginForm() {
const { login, loading, error } = useStore(
useShallow((state) => ({
login: state.login,
loading: state.loading,
error: state.error,
}))
);

const handleSubmit = (e) => {
e.preventDefault();
login(e.target.username.value, e.target.password.value);
};

return (
<form onSubmit={handleSubmit}>
<input name="username" placeholder="用户名" />
<input name="password" type="password" placeholder="密码" />
<button disabled={loading}>{loading ? '登录中...' : '登录'}</button>
{error && <p style={{ color: 'red' }}>{error}</p>}
</form>
);
}

function CartIcon() {
const cartCount = useStore((state) =>
state.cart.reduce((sum, item) => sum + item.quantity, 0)
);
return <span>🛒 {cartCount}</span>;
}

function Dashboard() {
const { user, logout, cart, addToCart } = useStore(
useShallow((state) => ({
user: state.user,
logout: state.logout,
cart: state.cart,
addToCart: state.addToCart,
}))
);

if (!user) return <LoginForm />;

return (
<div>
<h2>欢迎,{user.name}!</h2>
<button onClick={logout}>退出登录</button>
<CartIcon />
<hr />
<h3>商品列表</h3>
<button onClick={() => addToCart({ id: 1, name: '商品A', price: 99 })}>
添加商品A
</button>
<p>购物车:{cart.length} 件</p>
</div>
);
}

export default function App() {
return <Dashboard />;
}

设计要点

  • Store 按功能域划分模块(用户、购物车、通用),但都位于同一个 create 调用中。Zustand 鼓励小型 Store,必要时可以拆分为多个独立的 Store。
  • 所有修改函数使用 set 的回调模式(set(state => ...)),确保基于最新状态计算新值。
  • persist 中间件的 partialize 过滤掉 loadingerror,避免刷新页面后仍显示“加载中”。
  • devtools 中间件的 actionName 参数为每次状态变更命名,方便在 Redux DevTools 中追踪操作历史。
  • 组件中使用 useShallow 订阅多个字段,避免因返回新对象引用导致不必要的渲染。

课后练习

一、概念自测(选择题 / 填空题)

  1. (单选) Zustand 中,create 回调函数接收的参数是什么?
    A. (dispatch, getState)
    B. (set, get)
    C. (state, action)
    D. (store, middleware)

  2. (单选) Zustand 的 persist 中间件默认将状态持久化到哪里?
    A. sessionStorage
    B. localStorage
    C. IndexedDB
    D. Cookie

  3. (填空) 在 Zustand 中,要在异步回调里读取最新的状态而不触发重新渲染,应使用 ______ 函数。

  4. (多选) 以下关于 Zustand 的描述,哪些是正确的?
    A. 使用 Zustand 必须在根组件包裹 <Provider>
    B. 异步 action 可以直接定义为 async 函数,无需额外中间件。
    C. Zustand 的修改函数引用是稳定的,可以安全地传递给 React.memo 子组件。
    D. Zustand 可以在组件外通过 getState()setState() 操作 Store。

二、AI 编程任务:编写面向 AI 的提示词

场景:你需要使用 Zustand 创建一个全局通知管理 Store。要求如下:

  • Store 状态包含 notifications 数组,每条通知包含 { id, type, message, timestamp }
  • 提供 addNotification(type, message) 方法,自动生成唯一 ID 和时间戳,并将通知加入数组。
  • 提供 removeNotification(id) 方法,根据 ID 删除通知。
  • 提供 clearAll() 方法,清空所有通知。
  • 使用 devtools 中间件连接 Redux DevTools,为每个操作命名。
  • 使用 persist 中间件持久化通知(可选:可以自定义 partialize 排除临时数据)。
  • 创建一个 NotificationCenter 组件,显示所有通知,并支持手动关闭单条和清空全部。

任务要求:请写出一段完整的中文提示词,发送给 AI,使其生成符合上述要求的 Store 和组件的完整代码。提示词中需明确指定中间件的配置方式、操作命名规范以及组件的渲染逻辑。

三、Agent 模式下的提示词示例

你是一个资深前端开发 Agent。请使用 Zustand 创建一个全局通知管理系统。需要创建以下文件:

  1. src/store/notificationStore.js
    • 使用 create,导入并组合 devtoolspersist 中间件。
    • State:{ notifications: [] }
    • addNotification(type, message):生成 { id: Date.now(), type, message, timestamp: Date.now() },通过回调形式 set(state => ...) 加入数组。set 第三个参数命名为 'notifications/add'
    • removeNotification(id):通过 id 过滤掉对应通知。第三个参数 'notifications/remove'
    • clearAll():设置 notifications: []。第三个参数 'notifications/clear'
    • persist 配置:name: 'notification-storage'partialize: (state) => ({ notifications: state.notifications })
    • devtools 配置:name: 'NotificationStore'
    • 导出 Hook useNotificationStore
  2. src/components/NotificationCenter.jsx
    • 使用 useNotificationStoreuseShallow 获取 notificationsremoveNotificationclearAll
    • 渲染通知列表:每条通知根据 type'success' 绿色、'error' 红色、'info' 蓝色、'warning' 橙色)设置不同背景色。显示消息和相对时间(如“1 分钟前”)。
    • 每条通知右侧有关闭按钮,点击调用 removeNotification(id)
    • 底部有“清空全部”按钮。
  3. 所有文件添加 JSDoc 注释,确保可直接运行。完成后列出所有文件内容。

四、面试真题与参考答案

题目(腾讯前端面试题):

请对比 Zustand 和 Redux Toolkit 的设计理念和适用场景。在什么情况下 Zustand 的“无 Provider”设计会是一个优势?Zustand 如何在组件外部访问 Store?这种能力适合解决什么问题?请举例说明。

参考答案

Zustand 的设计理念是极简和透明——状态就是一个普通的 JavaScript 对象,修改函数定义在旁边,无需 Provider 包裹、无需 action type 常量、无需 dispatch。Redux Toolkit 的设计理念是结构化与标准化——通过 Slice、Reducer、Thunk 等明确的概念划分,强制团队按照统一模式编写状态逻辑,适合大型协作项目。Zustand 适合中小型应用、快速原型、或与 Redux 混合使用管理 UI 状态;Redux Toolkit 适合大型应用,尤其是利用 RTK Query 管理服务端数据缓存。

Zustand 的“无 Provider”设计的优势:在多包 monorepo 或微前端场景下,不同子应用可能需要各自独立的 Store,无需共享同一个 Provider 层级。在将 Zustand Store 用于纯逻辑模块(非 React 组件)时,无需模拟 React 环境即可测试和使用。组件树的任何部分都可以按需引入 Store,无需考虑 Provider 的嵌套层级。

Zustand 在组件外部访问 Store 使用 store.getState()store.setState()。这种能力适合解决非 UI 逻辑的状态交互:例如 WebSocket 消息处理(消息到达后直接更新 Store,无需通过组件中转)、定时器回调、第三方 SDK 集成、Node.js 中间件等。举例:一个全局的 WebSocket 管理器,接收到消息后调用 useChatStore.getState().addMessage(msg) 更新聊天记录,无需将 React 组件树暴露给 WebSocket 逻辑。


课后练习答案

一、概念自测答案

  1. B

    • 解析:create((set, get) => ({ ... })) 接收 setget 两个函数。A 是 Redux useReducer 的参数;C 是 Redux Reducer 的参数;D 不是 Zustand 的 API。
  2. B

    • 解析:persist 中间件默认使用 localStorage 进行持久化。可通过 storage 选项修改为 sessionStorage 或自定义存储引擎。
  3. get

    • 解析:get() 返回 Store 的最新状态快照,适合在异步回调、定时器或事件处理中读取状态而不触发 React 渲染。
  4. B、C、D

    • 解析:A 错误,Zustand 不需要 Provider 包裹组件树。B 正确,异步操作可直接写 async 函数。C 正确,create 中定义的函数引用在 Store 生命周期中保持稳定。D 正确,getState()setState() 可在组件外使用。

二、AI 编程任务参考答案(提示词示例)

示例提示词
“请使用 Zustand 创建一个全局通知 Store 和展示组件。要求:

  • Store 使用 create,组合 devtoolspersist 中间件。State 包含 notifications 数组。
  • 提供 addNotification(type, message)removeNotification(id)clearAll() 三个操作,为每个 set 调用添加 action name。
  • persist 的 name 为 'notification-storage'partialize 仅持久化 notifications
  • NotificationCenter 组件:展示所有通知,类型对应不同颜色,支持单条关闭和全部清空。
  • 使用 useShallow 订阅多个字段。输出 store 和组件的完整代码。”
CATALOG
  1. 1. 第101课:Zustand 轻量状态管理——创建 Store、异步 action、中间件、与 Redux 对比
    1. 1.1. 1. Zustand 的核心哲学与安装
      1. 1.1.1. 1.1 安装
    2. 1.2. 2. 创建 Store 与基本读写
      1. 1.2.1. 2.1 create 函数
      2. 1.2.2. 2.2 在组件中读取状态
      3. 1.2.3. 2.3 在组件中修改状态
      4. 1.2.4. 2.4 在组件外部访问 Store
    3. 1.3. 3. 异步 Action
    4. 1.4. 4. 中间件
      1. 1.4.1. 4.1 persist:持久化到 localStorage
      2. 1.4.2. 4.2 devtools:集成 Redux DevTools
      3. 1.4.3. 4.3 immer:简化不可变更新
      4. 1.4.4. 4.4 组合多个中间件
    5. 1.5. 5. Zustand 与 Redux Toolkit 对比
    6. 1.6. 6. 综合实战:全局购物车与用户认证
    7. 1.7. 课后练习
      1. 1.7.1. 一、概念自测(选择题 / 填空题)
      2. 1.7.2. 二、AI 编程任务:编写面向 AI 的提示词
      3. 1.7.3. 三、Agent 模式下的提示词示例
      4. 1.7.4. 四、面试真题与参考答案
    8. 1.8. 课后练习答案
      1. 1.8.1. 一、概念自测答案
      2. 1.8.2. 二、AI 编程任务参考答案(提示词示例)