redux vs jotai vs mobx-react-lite vs react-query vs recoil vs zustand
React 状态管理与数据获取方案对比
reduxjotaimobx-react-litereact-queryrecoilzustand类似的npm包:

React 状态管理与数据获取方案对比

jotai、mobx-react-lite、react-query、recoil、redux 和 zustand 都是 React 生态中用于管理应用状态或处理异步数据的主流库,但它们解决的问题、设计哲学和适用场景各有不同。redux 是最经典的状态容器,强调可预测性和中间件生态;zustand 和 jotai 提供更轻量、简洁的原子化状态模型;recoil 由 Meta 推出,以图状依赖和派生状态为核心;mobx-react-lite 基于响应式编程,通过可观察对象自动追踪依赖;而 react-query(现为 TanStack Query)专注于服务端状态管理,如缓存、同步和后台更新,不直接处理 UI 状态。这些库可以单独使用,也可根据需求组合(如用 zustand 管理 UI 状态 + react-query 管理服务端数据)。

npm下载趋势

3 年

GitHub Stars 排名

统计详情

npm包名称
下载量
Stars
大小
Issues
发布时间
License
redux50,698,85461,491290 kB183 年前MIT
jotai6,851,68821,282112 kB219 天前MIT
mobx-react-lite4,382,81528,215351 kB453 天前MIT
react-query1,952,15350,3682.26 MB1754 年前MIT
recoil019,4202.21 MB3204 年前MIT
zustand058,76395.2 kB71 个月前MIT

React 状态管理与数据获取方案深度对比

在现代 React 开发中,状态管理早已不是“是否需要”的问题,而是“如何选型”。本文将深入对比 jotai、mobx-react-lite、react-query、recoil、redux 和 zustand 六大主流方案,从核心理念、代码风格、适用边界到真实工程权衡,帮助你做出精准技术决策。

🧠 核心定位:UI 状态 vs 服务端状态

首先必须明确:并非所有库都解决同一类问题。

  • UI 状态管理:jotai、mobx-react-lite、recoil、redux、zustand 主要用于管理客户端 UI 状态(如表单输入、模态框开关、主题设置等)。
  • 服务端状态管理:react-query 专为服务端数据(如 API 响应)设计,提供缓存、同步、失效等机制,不应用于存储 UI 状态。

💡 实践建议:多数应用应同时使用两类工具 —— 例如用 zustand 管理 UI 状态,用 react-query 管理用户资料、文章列表等服务端数据。

下面我们将聚焦于 UI 状态管理库的对比(react-query 会在专门章节说明)。

🧩 状态模型:原子化 vs 全局 Store vs 响应式对象

jotai:原子化状态(Atom-based)

jotai 将状态拆分为独立的“原子”(atoms),组件直接读写原子,依赖自动追踪。

// jotai
import { atom, useAtom } from 'jotai';

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

function Counter() {
  const [count, setCount] = useAtom(countAtom);
  const double = useAtomValue(doubleCountAtom);
  return <div>{count} → {double}</div>;
}

zustand:单一 Store + Hooks

zustand 使用单一 store,但通过 Hooks 暴露部分状态,避免全量重渲染。

// zustand
import { create } from 'zustand';

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

function Counter() {
  const { count, double, inc } = useStore();
  return <div>{count} → {double()}</div>;
}

recoil:原子 + 选择器(Selectors)

recoil 的原子(atom)类似 jotai,但派生状态通过 selector 显式定义。

// recoil
import { atom, selector, useRecoilState, useRecoilValue } from 'recoil';

const countAtom = atom({ key: 'count', default: 0 });
const doubleCountSelector = selector({
  key: 'doubleCount',
  get: ({ get }) => get(countAtom) * 2
});

function Counter() {
  const [count, setCount] = useRecoilState(countAtom);
  const double = useRecoilValue(doubleCountSelector);
  return <div>{count} → {double}</div>;
}

redux:不可变全局 Store

redux 要求通过 reducer 函数更新不可变状态,通常配合 Redux Toolkit 简化。

// redux + RTK
import { createSlice, configureStore } from '@reduxjs/toolkit';
import { useSelector, useDispatch } from 'react-redux';

const counterSlice = createSlice({
  name: 'counter',
  initialState: { count: 0 },
  reducers: {
    increment: (state) => { state.count += 1; }
  }
});

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

function Counter() {
  const count = useSelector(state => state.count);
  const dispatch = useDispatch();
  return <div>{count} → {count * 2}</div>;
}

mobx-react-lite:响应式对象

mobx-react-lite 将状态定义为可观察对象,修改属性自动触发重渲染。

// mobx-react-lite
import { makeAutoObservable } from 'mobx';
import { observer } from 'mobx-react-lite';

class CounterStore {
  count = 0;
  constructor() { makeAutoObservable(this); }
  get double() { return this.count * 2; }
  increment = () => { this.count++; };
}

const store = new CounterStore();

const Counter = observer(() => (
  <div>{store.count} → {store.double}</div>
));

⚡ 性能与重渲染控制

所有库都致力于避免不必要的重渲染,但实现方式不同:

  • jotai / recoil:基于原子依赖,仅当所用原子变化时重渲染。
  • zustand:通过 useStore(selector) 选择部分状态,类似 useSelector。
  • redux:依赖 useSelector 的浅比较或自定义比较函数。
  • mobx-react-lite:自动追踪组件内访问的可观察属性,仅当这些属性变化时重渲染。
// zustand: 选择部分状态避免重渲染
const count = useStore(state => state.count); // 只有 count 变化时重渲染

// redux: 同样需选择
const count = useSelector(state => state.count);

🌐 异步与副作用处理

react-query:服务端状态的黄金标准

react-query 不管理 UI 状态,而是处理 API 数据的获取、缓存和同步:

// react-query
import { useQuery, useMutation } from '@tanstack/react-query';

function UserProfile({ userId }) {
  const { data, isLoading } = useQuery({
    queryKey: ['user', userId],
    queryFn: () => fetchUser(userId)
  });

  const mutation = useMutation({
    mutationFn: updateUser,
    onSuccess: () => queryClient.invalidateQueries(['user', userId])
  });

  if (isLoading) return <div>Loading...</div>;
  return <div>{data.name}</div>;
}

其他 UI 状态库通常不内置异步逻辑,需自行集成:

  • redux:通过 middleware(如 Redux Thunk)
  • zustand / jotai:在 action 中直接使用 async/await
  • mobx:在 action 中处理异步
// zustand with async
const useStore = create((set) => ({
  user: null,
  fetchUser: async (id) => {
    const user = await api.getUser(id);
    set({ user });
  }
}));

🔧 开发体验与调试

  • redux:拥有最完善的 DevTools(时间旅行、action 日志),但需额外配置。
  • mobx-react-lite:DevTools 支持良好,可查看响应式依赖树。
  • recoil / jotai / zustand:DevTools 支持较弱,主要依赖 React DevTools。
  • react-query:提供专属 DevTools,可视化查询状态、缓存和后台任务。

📦 适用场景总结

场景推荐方案
简单 UI 状态(< 5 个状态)zustand 或 jotai(极简 API)
复杂派生状态/依赖图recoil(selectors)或 jotai(派生 atoms)
面向对象风格/响应式偏好mobx-react-lite
企业级应用/严格可预测性redux + Redux Toolkit
重度 API 数据交互react-query(必须搭配 UI 状态库)

🚫 过时警告

截至 2024 年,所有列出的包均处于积极维护状态,无官方弃用声明。但需注意:

  • recoil 的 GitHub 仓库更新频率已显著降低,Meta 未明确其未来路线图,新项目需谨慎评估。
  • mobx-react-lite 是 mobx-react 的轻量替代,后者已不推荐用于新项目。

💡 最终建议

  • 不要用 react-query 管理 UI 状态 —— 它的设计目标完全不同。
  • 中小项目优先考虑 zustand 或 jotai —— 它们用最少的代码解决 90% 的状态问题。
  • 大型团队或遗留系统 —— redux 的规范性和工具链仍是安全选择。
  • 已有 MobX 经验 —— mobx-react-lite 能最大化开发效率。

状态管理没有银弹,但理解每个工具的“心智模型”和边界,能让你在正确的地方用正确的工具 —— 这才是专业前端架构的核心。

如何选择: redux vs jotai vs mobx-react-lite vs react-query vs recoil vs zustand

  • redux:

    选择 redux 如果你要求严格的状态可预测性、时间旅行调试、成熟的中间件生态(如 Redux Thunk/Saga)或需要与现有 Redux 工具链集成。它适合大型企业级应用,但样板代码较多,需搭配 Redux Toolkit 才能简化开发体验。

  • jotai:

    选择 jotai 如果你希望使用极简 API 实现细粒度状态更新,且偏好原子化(atom-based)模型而非全局 store。它天然支持 React 并发特性,适合中小型项目或希望避免样板代码的团队。但注意其生态系统不如 Redux 成熟,复杂状态逻辑可能需要额外封装。

  • mobx-react-lite:

    选择 mobx-react-lite 如果你倾向于面向对象的响应式编程风格,希望状态变更自动触发重渲染而无需手动订阅。它适合已有 MobX 经验的团队或需要高性能细粒度更新的场景,但需理解其“可观察对象”和“动作”概念,且对不可变数据模式支持较弱。

  • react-query:

    选择 react-query 如果你的应用重度依赖服务端数据(如 REST 或 GraphQL),需要开箱即用的缓存、去重、后台刷新、乐观更新等能力。它专为服务端状态设计,不应替代 UI 状态管理,但可与任何 UI 状态库(如 Zustand)配合使用。

  • recoil:

    选择 recoil 如果你需要强大的派生状态(selectors)和异步状态支持,且希望状态以图结构组织。它由 Meta 维护,适合大型应用中复杂的依赖关系,但学习曲线较陡,且社区活跃度近年有所下降,需评估长期维护风险。

  • zustand:

    选择 zustand 如果你想要一个零样板、Hooks 风格的全局状态管理方案,且不需要时间旅行调试。它基于单一 store 但支持模块化拆分,API 极简,适合大多数中小型项目,性能表现优秀,是现代 React 应用的轻量级首选。

redux的README

Redux Logo

Redux is a predictable state container for JavaScript apps.

It helps you write applications that behave consistently, run in different environments (client, server, and native), and are easy to test. On top of that, it provides a great developer experience, such as live code editing combined with a time traveling debugger.

You can use Redux together with React, or with any other view library. The Redux core is tiny (2kB, including dependencies), and has a rich ecosystem of addons.

Redux Toolkit is our official recommended approach for writing Redux logic. It wraps around the Redux core, and contains packages and functions that we think are essential for building a Redux app. Redux Toolkit builds in our suggested best practices, simplifies most Redux tasks, prevents common mistakes, and makes it easier to write Redux applications.

GitHub Workflow Status npm version npm downloads redux channel on discord

Installation

Create a React Redux App

The recommended way to start new apps with React and Redux Toolkit is by using our official Redux Toolkit + TS template for Vite, or by creating a new Next.js project using Next's with-redux template.

Both of these already have Redux Toolkit and React-Redux configured appropriately for that build tool, and come with a small example app that demonstrates how to use several of Redux Toolkit's features.

# Vite with our Redux+TS template
# (using the `degit` tool to clone and extract the template)
npx degit reduxjs/redux-templates/packages/vite-template-redux my-app

# Next.js using the `with-redux` template
npx create-next-app --example with-redux my-app

We do not currently have official React Native templates, but recommend these templates for standard React Native and for Expo:

npm install @reduxjs/toolkit react-redux

For the Redux core library by itself:

npm install redux

For more details, see the Installation docs page.

Documentation

The Redux core docs are located at https://redux.js.org, and include the full Redux tutorials, as well usage guides on general Redux patterns:

The Redux Toolkit docs are available at https://redux-toolkit.js.org, including API references and usage guides for all of the APIs included in Redux Toolkit.

Learn Redux

Redux Essentials Tutorial

The Redux Essentials tutorial is a "top-down" tutorial that teaches "how to use Redux the right way", using our latest recommended APIs and best practices. We recommend starting there.

Redux Fundamentals Tutorial

The Redux Fundamentals tutorial is a "bottom-up" tutorial that teaches "how Redux works" from first principles and without any abstractions, and why standard Redux usage patterns exist.

Help and Discussion

The #redux channel of the Reactiflux Discord community is our official resource for all questions related to learning and using Redux. Reactiflux is a great place to hang out, ask questions, and learn - please come and join us there!

Before Proceeding Further

Redux is a valuable tool for organizing your state, but you should also consider whether it's appropriate for your situation. Please don't use Redux just because someone said you should - instead, please take some time to understand the potential benefits and tradeoffs of using it.

Here are some suggestions on when it makes sense to use Redux:

  • You have reasonable amounts of data changing over time
  • You need a single source of truth for your state
  • You find that keeping all your state in a top-level component is no longer sufficient

Yes, these guidelines are subjective and vague, but this is for a good reason. The point at which you should integrate Redux into your application is different for every user and different for every application.

For more thoughts on how Redux is meant to be used, please see:

Basic Example

The whole global state of your app is stored in an object tree inside a single store. The only way to change the state tree is to create an action, an object describing what happened, and dispatch it to the store. To specify how state gets updated in response to an action, you write pure reducer functions that calculate a new state based on the old state and the action.

Redux Toolkit simplifies the process of writing Redux logic and setting up the store. With Redux Toolkit, the basic app logic looks like:

import { createSlice, configureStore } from '@reduxjs/toolkit'

const counterSlice = createSlice({
  name: 'counter',
  initialState: {
    value: 0
  },
  reducers: {
    incremented: state => {
      // Redux Toolkit allows us to write "mutating" logic in reducers. It
      // doesn't actually mutate the state because it uses the Immer library,
      // which detects changes to a "draft state" and produces a brand new
      // immutable state based off those changes
      state.value += 1
    },
    decremented: state => {
      state.value -= 1
    }
  }
})

export const { incremented, decremented } = counterSlice.actions

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

// Can still subscribe to the store
store.subscribe(() => console.log(store.getState()))

// Still pass action objects to `dispatch`, but they're created for us
store.dispatch(incremented())
// {value: 1}
store.dispatch(incremented())
// {value: 2}
store.dispatch(decremented())
// {value: 1}

Redux Toolkit allows us to write shorter logic that's easier to read, while still following the original core Redux behavior and data flow.

Logo

You can find the official logo on GitHub.

Change Log

This project adheres to Semantic Versioning. Every release, along with the migration instructions, is documented on the GitHub Releases page.

License

MIT