【React】Redux、Recoil、jotai、zustand 几个状态管理库的对比

Redux

核心概念:

单一数据源:所有的状态存储在一个全局的 store 中 状态是只读的: 只能通过派发 action 来修改状态 纯函数 Reducer: 状态的修改只能通过纯函数 reducer 处理,接收当前状态和 action,返回新状态

使用方式

1、创建 Store

javascript 复制代码
import { createStore } from 'redux';

const initialState = { count: 0 };
const reducer = (state = initialState, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return { ...state, count: state.count + 1 };
    default:
      return state;
  }
};
const store = createStore(reducer);


store.subscribe(() => console.log(store.getState()))  
  
// 改变内部状态的唯一方法是 dispatch 一个 action。  
store.dispatch({ type: 'INCREMENT' })  

Redux-toolkit 的写法,消除 Redux 逻辑中的【样板代码】,看上去是简化了不少。 主要做的事情有

  • configureStore 通过函数调用设置一个配置完善的 Redux store, 包括合并 reducer,添加 thunk 中间件以及设置 Redux DevTool 集成。
javascript 复制代码
import { configureStore } from '@reduxjs/toolkit'
import todosReducer from '../features/todos/todosSlice'
import filtersReducer from '../features/filters/filtersSlice'

export const store = configureStore({
  reducer: {
    todos: todosReducer,
    filters: filtersReducer
  }
})
  • createSlice 使用 Immer 库来编写 reducer,可以使用 "mutating JS" 语法,比如 state.value = 123, 不需要使用扩展运算符。内部基于你的 reducer 名称生成 action type 字符串。 action createors 和 action type 都自动生成了
go 复制代码
// 最原始的写法
const reducer = (state = initialState, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return { ...state, count: state.count + 1 };
    default:
      return state;
  }
};
css 复制代码
// 使用 redux-tookit
 reducers: {
    incremented: state => {
      state.value += 1
    }

完整的使用 redux-tookit的例子

ts 复制代码
import { createSlice, configureStore } from '@reduxjs/toolkit'

const counterSlice = createSlice({
  name: 'counter',
  initialState: {
    value: 0
  },
  reducers: {
    incremented: state => {
      // Redux Toolkit 允许在 reducers 中编写 "mutating" 逻辑。
      // 它实际上并没有改变 state,因为使用的是 Immer 库,检测到"草稿 state"的变化并产生一个全新的
      // 基于这些更改的不可变的 state。
      state.value += 1
    },
    decremented: state => {
      state.value -= 1
    }
  }
})

export const { incremented, decremented } = counterSlice.actions

const store = configureStore({
  reducer: counterSlice.reducer
})

// 可以订阅 store
store.subscribe(() => console.log(store.getState()))

// 将我们所创建的 action 对象传递给 `dispatch`
store.dispatch(incremented())
// {value: 1}

总结是用 redux toolkit 的好处

  • Redux Toolkit 消除手写的 action creator 、action type的需求
  • Redux Toolkit 消除了容易出错的手动不可变更新逻辑的需求
  • Redux Toolkit 通过单一清晰的函数调用简化 store 设置,同时保留完全配置 store 选项的能力

Recoil

核心概念

  • Atom: 最小的状态单元,类似于 Redux 的 State
  • Selectors: 基于 atom 的派生状态,类似于计算属性
  • React 集成: 通过 Hook(如 useRecoilState)直接与 React 组件绑定
ts 复制代码
import { atom, selector, useRecoilState } from 'recoil';

const countState = atom({
  key: 'countState',
  default: 0,
});

const doubleCount = selector({
  key: 'doubleCount',
  get: ({ get }) => get(countState) * 2,
});

Jotai

核心概念: 类似 Recoil 的原子化状态管理,但是更加轻量,强调组合型和简洁 API

底层原理:

  • Atom: 通过 atom() 定义原子状态,原子之间可以组合(类似函数式编程)
  • Atoms: 类似于 Recoil 的原子状态,但是更加简洁
  • 无 Provider: 不需要 Redux 或 Recoil 那样包裹组件
ts 复制代码
import { atom, useAtom } from 'jotai';

const countAtom = atom(0);
const doubleCountAtom = atom((get) => get(countAtom) * 2);

在组件中使用

ts 复制代码
const App = () => {
  const [count, setCount] = useAtom(countAtom);
  const [doubled] = useAtom(doubleCountAtom);

  return (
    <div>
      <p>Count: {count}</p>
      <p>Doubled: {doubled}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
};

Zustand

核心概念

  • 单一 Store: 类似 Redux
  • 函数更新:通过函数直接修改状态
  • 无 Action/Reducer:直接操作状态,减少复杂性

底层原理

  • Store: 状态存储在外部 JavaScript 对象中,通过 createStore 创建。
  • 发布-订阅模式: 组件通过useStore Hook 订阅状态变化,Store 内部维护一个订阅者列表,当状态变化时通知所有订阅者
  • 选择器(Selector): 支持传入选择器函数(如 useStore(state=>state.count)),通过钱比较避免重复渲染
  • Middleware 支持: 可以通过中间件扩展功能。
  • 脱离了 React Context:Zustand 不依赖 React Context 传递 Store,直接通过闭包和订阅机制管理状态,避免了 Context 层级问题
ts 复制代码
import { create } from 'zustand';

const useStore = create((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  doubleCount: (state) => state.count * 2,
}));

在组件中使用

javascript 复制代码
const App = () => {
  const { count, increment, doubleCount } = useStore();
  const doubled = useStore(doubleCount);

  return (
    <div>
      <p>Count: {count}</p>
      <p>Doubled: {doubled}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
};

对比总结

特性 Redux Recoil Jotai Zustand
状态模型 单一 Store 原子化状态 原子化状态 外部 Store
更新机制 Dispatch Action 直接更新 Atom 直接更新 Atom 直接修改 Store
性能优化 浅比较(需手动优化) 自动依赖追踪 自动依赖追踪 选择器 + 浅比较
异步支持 需中间件(如 Thunk) 内置异步 Selector 需手动处理 直接处理
与 React 集成 需 React-Redux 深度集成 深度集成 轻量集成
适用场景 大型复杂应用 细粒度状态管理 轻量原子化状态 简单全局状态
相关推荐
木叶丸3 分钟前
编程开发中,那些你必须掌握的基本概念
前端·数据结构·编程语言
前端进阶者4 分钟前
js通知提醒
前端·javascript
拖孩10 分钟前
微信群太多,管理麻烦?那试试接入AI助手吧~
前端·后端·微信
乌兰麦朵26 分钟前
Vue吹的颅内高潮,全靠选择性失明和 .value 的PUA!
前端·vue.js
Code季风27 分钟前
Gin Web 层集成 Viper 配置文件和 Zap 日志文件指南(下)
前端·微服务·架构·go·gin
蓝倾27 分钟前
如何使用API接口实现淘宝商品上下架监控?
前端·后端·api
舂春儿29 分钟前
如何快速统计项目代码行数
前端·后端
毛茸茸29 分钟前
⚡ 从浏览器到编辑器只需1秒,这个React定位工具改变了我的开发方式
前端
Pedantic29 分钟前
我们什么时候应该使用协议继承?——Swift 协议继承的应用与思
前端·后端
Software攻城狮30 分钟前
vite打包的简单配置
前端