【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 深度集成 深度集成 轻量集成
适用场景 大型复杂应用 细粒度状态管理 轻量原子化状态 简单全局状态
相关推荐
爱分享的鱼鱼1 分钟前
Vue中如何实现可切换显示/隐藏侧边栏的按钮
前端
Mike_jia4 分钟前
DBdoctor:数据库性能的“AI名医”,诊断效率提升10倍的终极利器
前端
怪可爱的地球人4 分钟前
向宇宙发送一枚小可爱
前端
数字元匠_山步8 分钟前
一篇笔记彻底搞懂 “脚手架” “框架” “构建工具” 的关系
前端
李剑一16 分钟前
前端实现时间轴组件拼接N多个不连续监控视频展示
前端·vue.js
岁月向前18 分钟前
iOS UI基础和内存管理相关
前端
Magicman23 分钟前
JS筑基(二)-关于this指向
前端
Asort24 分钟前
精通React JSX:高级开发者必备的语法规则与逻辑处理技巧
前端·javascript·react.js
Mintopia26 分钟前
想摸鱼背单词?我用 Cursor 一个小时开发了一个 Electron 应用
前端·javascript·cursor
JarvanMo29 分钟前
Flutter PruneKit - 从你的Flutter代码中干掉那些已经死掉的代码
前端