当时先说了redux,觉得不够说,再说了内置的useState、useContext和useReducer等钩子函数。(完了,开头就难倒了)
我们来介绍一下 Redux 和zustand, Recoil,以及简化版本 Jotai。我会用最简单的语言来讲解,让你快速理解它们的原理和用法。
1. Redux:通过 action 和 reducer 更新状态
核心概念: Redux 是一个状态管理库,它的核心思想是把整个应用的状态存储在一个单一的、不可变的 state tree(状态树)中。状态的更新需要通过一系列的步骤来完成,主要包括 action 和 reducer。
(1)Action
-
定义:Action 是一个普通的 JavaScript 对象,用来描述发生了什么。它必须有一个
type属性,表示动作的类型。 -
示例:
const addTodoAction = { type: "ADD_TODO", payload: "Learn Redux" };
(2)Reducer
-
定义:Reducer 是一个纯函数,它接收当前状态和一个 action,然后返回新的状态。
-
规则:Reducer 必须是纯函数,不能修改原状态,只能返回新的状态。
-
示例:
function todoReducer(state = [], action) { switch (action.type) { case "ADD_TODO": return [...state, action.payload]; default: return state; } }
(3)Store
-
定义:Store 是一个容器,用来保存状态树,并提供方法来更新状态。
-
如何使用:
import { createStore } from "redux"; const store = createStore(todoReducer); // 订阅状态变化 store.subscribe(() => console.log(store.getState())); // 派发 action 更新状态 store.dispatch({ type: "ADD_TODO", payload: "Learn Redux" });
(4)问题:Redux 太繁琐了!
Redux 的代码量较多,配置复杂,尤其是对于小型项目来说,显得有些“大炮打蚊子”。为了解决这个问题,出现了 Redux Toolkit。
2. Redux Toolkit:简化 Redux 的使用
核心工具: Redux Toolkit 是一个官方提供的工具包,用来简化 Redux 的开发。它内置了 createSlice 和 createAsyncThunk 等工具。
(1)createSlice
-
作用:简化 reducer 和 action 的创建过程。
-
示例:
import { createSlice } from "@reduxjs/toolkit"; const todoSlice = createSlice({ name: "todo", initialState: [], reducers: { addTodo(state, action) { state.push(action.payload); }, removeTodo(state, action) { state.splice(action.payload.index, 1); } } }); export const { addTodo, removeTodo } = todoSlice.actions; export default todoSlice.reducer;
(2)createAsyncThunk
-
作用:简化异步操作的处理。
-
示例:
import { createAsyncThunk } from "@reduxjs/toolkit"; // 异步 action const fetchTodos = createAsyncThunk("todos/fetchTodos", async () => { const response = await fetch("https://jsonplaceholder.typicode.com/todos"); return response.json(); });
(3)优点**
- 更简洁:代码量大幅减少。
- 更易用:内置了对异步操作的支持。
- 更安全:默认使用了不可变更新。
Zustand
Zustand 是一个基于 Hooks 的状态管理库,专为 React 设计,旨在提供一种简单而强大的状态管理方式。它的核心理念是“最小化”,即只管理应用中真正需要的状态,而不是强迫使用全局状态,从而提高性能和可维护性 (看中zustand的小巧和按需订阅模式)
1. 安装 Zustand
npm install zustand
或者使用 yarn:
yarn add zustand
2. 创建 Store
使用 create 函数创建一个 store,store 是一个 JavaScript 对象,包含状态和修改状态的方法。
import create from 'zustand';
const useStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
}));
3. 在组件中使用 Store
通过 useStore Hook 访问和更新状态。
import React from 'react';
import { useStore } from './store';
const Counter = () => {
const { count, increment, decrement } = useStore();
return (
<div>
<h1>{count}</h1>
<button onClick={increment}>+1</button>
<button onClick={decrement}>-1</button>
</div>
);
};
四、高级功能
1. 异步操作
Zustand 支持异步操作,例如从 API 获取数据。
import create from 'zustand';
const useStore = create((set) => ({
user: null,
loading: false,
fetchUser: async (id) => {
set({ loading: true });
try {
const response = await fetch(`https://api.example.com/users/${id}`);
const user = await response.json();
set({ user, loading: false });
} catch (error) {
set({ loading: false, error });
}
},
}));
2. 状态持久化
通过 persist 中间件,可以将状态持久化到 localStorage 或 sessionStorage。
import create from 'zustand';
import { persist } from 'zustand/middleware';
const useStore = create(
persist(
(set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
}),
{ name: 'counter-storage' }
)
);
3. 中间件支持
Zustand 支持多种中间件,例如 devtools 中间件,可以在浏览器开发者工具中调试状态。
import create from 'zustand';
import { devtools } from 'zustand/middleware';
const useStore = create(
devtools((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
}))
);
zustand 小结
zustand 通过gzip 压缩后仅1kb,对项目性能几乎没有影响。通过按需订阅模式,减少不必要的组件渲染。在灵活方面,支持异步,使用persist中间件进行持久化,也支持devtool 适用开发调试。但是社区相比redux 小了点,资源有限,高级功能也少了点。
3. Recoil:Facebook 推出的状态管理库
核心概念: Recoil 是 Facebook 推出的一个状态管理库,它基于 原子(atom) 和 选择器(selector) 的概念,支持细粒度的状态管理。
(1)原子(Atom)
-
定义:原子是状态的基本单位,类似于 Redux 中的
state。 -
示例:
import { atom } from "recoil"; const todoAtom = atom({ key: "todoAtom", default: [] });
(2)选择器(Selector)
-
定义:选择器是一个函数,可以根据原子的状态计算出新的状态。
-
示例:
import { selector } from "recoil"; const todoCountSelector = selector({ key: "todoCountSelector", get: ({ get }) => { const todos = get(todoAtom); return todos.length; } });
(3)使用
-
在组件中使用:
import { useRecoilState, useRecoilValue } from "recoil"; function TodoList() { const [todos, setTodos] = useRecoilState(todoAtom); const todoCount = useRecoilValue(todoCountSelector); return ( <div> <h1>Todo Count: {todoCount}</h1> <ul> {todos.map((todo, index) => ( <li key={index}>{todo}</li> ))} </ul> <button onClick={() => setTodos([...todos, "New Todo"])}> Add Todo </button> </div> ); }
(4)优点**
- 细粒度管理:可以精确控制状态的更新。
- 自动缓存:选择器的结果会被自动缓存,减少重复计算。
- 与 React 高度集成:使用起来非常自然。
4. Jotai:简化版的 Recoil
核心概念: Jotai 是一个类似 Recoil 的状态管理库,但它更简化,API 更简洁。
(1)原子(Atom)
-
定义:Jotai 也使用原子作为状态的基本单位。
-
示例:
import { atom } from "jotai"; const todoAtom = atom([]);
(2)使用
-
在组件中使用:
import { useAtom } from "jotai"; function TodoList() { const [todos, setTodos] = useAtom(todoAtom); return ( <div> <ul> {todos.map((todo, index) => ( <li key={index}>{todo}</li> ))} </ul> <button onClick={() => setTodos([...todos, "New Todo"])}> Add Todo </button> </div> ); }
(3)优点**
- API 简洁:比 Recoil 更简单,适合快速上手。
- 轻量级:体积小,性能好。
- 易于扩展:可以方便地与其他库结合使用。
总结
| 库 | 特点 | 优点 | 缺点 |
|---|---|---|---|
| Redux | 通过 action 和 reducer 更新状态,结构清晰,适合复杂应用。 | 功能强大,社区支持多。 | 配置繁琐,代码量多。 |
| Redux Toolkit | 简化了 Redux 的使用,内置 createSlice 和 createAsyncThunk。 | 代码更简洁,支持异步操作。 | 仍然需要理解 Redux 的核心概念。 |
| Recoil | 基于原子和选择器,支持细粒度状态管理,自动缓存。 | 细粒度管理,与 React 高度集成。 | API 较复杂,学习曲线稍陡。 |
| Jotai | 类似 Recoil,但更简化,API 更简洁。 | API 简洁,轻量级,易于上手。 | 功能相对有限,适合小型项目。 |