【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 深度集成 深度集成 轻量集成
适用场景 大型复杂应用 细粒度状态管理 轻量原子化状态 简单全局状态
相关推荐
独行soc2 分钟前
2025年常见渗透测试面试题-红队面试宝典下(题目+回答)
linux·运维·服务器·前端·面试·职场和发展·csrf
uhakadotcom18 分钟前
Google Earth Engine 机器学习入门:基础知识与实用示例详解
前端·javascript·面试
麓殇⊙33 分钟前
Vue--组件练习案例
前端·javascript·vue.js
outstanding木槿36 分钟前
React中 点击事件写法 的注意(this、箭头函数)
前端·javascript·react.js
会点php的前端小渣渣40 分钟前
vue的计算属性computed的原理和监听属性watch的原理(新)
前端·javascript·vue.js
_一条咸鱼_2 小时前
深入解析 Vue API 模块原理:从基础到源码的全方位探究(八)
前端·javascript·面试
患得患失9492 小时前
【前端】【难点】前端富文本开发的核心难点总结与思路优化
前端·富文本
执键行天涯2 小时前
在vue项目中package.json中的scripts 中 dev:“xxx“中的xxx什么概念
前端·vue.js·json
雯0609~2 小时前
html:文件上传-一次性可上传多个文件,将文件展示到页面(可删除
前端·html
涵信2 小时前
2024年React最新高频面试题及核心考点解析,涵盖基础、进阶和新特性,助你高效备战
前端·react.js·前端框架