Vuex、Flux、Redux、Redux-Saga、Dva、MobX:状态管理思想与现代实践
原文试图把 Store、Flux、Redux、Vuex、Redux-Saga、Dva 和 MobX 放在一条演进路径中。这个主线仍有学习价值,但原文的部分示例是抓取后的损坏代码,且 Redux、Vuex、Pinia、MobX 的推荐用法已经变化。
本文尽量保留原文的概念、比较和历史代码,同时区分:
- 历史模型:用于理解 Flux/Redux/Vuex 早期设计;
- 当前推荐:Redux Toolkit、Pinia、MobX 6 等新项目写法;
- Vue 2/3 边界:Vuex 3/4 与 Pinia 2/3 不能混为一谈。
一、为什么需要状态管理?
不管使用 Vue、React 还是其他 UI 框架,应用都需要管理状态(state):
- 一个组件需要读取另一个组件的数据;
- 一个组件需要改变另一个组件使用的数据;
- 多个页面共享登录用户、权限、购物车、主题或请求缓存;
- 状态变化需要可追踪、可调试、可测试。
父子组件可以通过 props/emits 通信,兄弟组件可以提升状态到共同父组件,跨层级可以使用 provide/inject。问题变复杂后,如果每个组件都能随意改全局变量,就很难回答:
- 这个状态什么时候改变的?
- 是谁改变的?
- 变化是否符合业务规则?
- 页面为什么重新渲染?
- 如何在测试中复现某一次状态变化?
状态管理模式的基本思路是:
把需要共享的状态抽取出来,使用明确的更新约定,让状态变化可预测,并让 UI 订阅状态变化。
这不是说所有状态都应该放进 Store。只被一个组件使用的输入框、弹窗开关和临时表单状态,通常放在组件本地更简单。
二、最简单的 Store 模式
最简单的实现是把状态放到外部变量中,例如 Vue 2 时代常见的 this.$root.$data 或模块级变量:
const state = {
message: 'Hello!',
}
function setMessage(value) {
state.message = value
}
function clearMessage() {
state.message = ''
}
如果所有代码都能直接修改 state.message,状态变化就没有统一入口。于是可以约定组件不直接修改 state,而是通过 action/function 修改:
const store = {
state: {
message: 'Hello!',
},
setMessage(value) {
this.state.message = value
},
clearMessage() {
this.state.message = ''
},
}
这样做至少有几个好处:
- 可以在统一入口打印日志;
- 可以增加权限、校验和持久化;
- 可以在测试中单独调用更新函数;
- 可以进一步演进成单向数据流。
这仍然只是约定。如果 store.state.message = 'x' 仍然公开可写,任何组件都可以绕过 action。严格限制需要库提供运行时约束或团队规范。

三、Flux:单向数据流思想
Flux 不是一个唯一的库,而是一种架构思想。经典 Flux 通常包含:
View -> Action -> Dispatcher -> Store -> View
它可以描述为四个部分:
- View:展示 Store 中的数据,也产生用户操作;
- Action:描述发生了什么,例如
ADD_USER; - Dispatcher:接收 action,并分发给注册的 Store;
- Store:保存状态,根据 action 更新自身并通知 View。

Flux 的核心约束是数据单向流动:
- View 产生 action;
- Dispatcher 把 action 分发给 Store;
- Store 根据 action 更新状态;
- Store 变化后通知 View;
- View 重新读取 Store。
原文说 Dispatcher 会把所有 Action 发给所有 Store,这符合经典 Flux Dispatcher 的注册回调模型。实际框架可以在 Store 内判断自己是否关心这个 action,也可以使用更细的事件路由;不要把“所有 Store 都必须处理所有 action”理解成硬性要求。
Flux 解决的是可追踪和单向流动问题,但多个 Store 之间的依赖、异步处理和样板代码也会增加复杂度。Redux 从 Flux 中吸收了单向数据流思想,同时简化了 Dispatcher/Store 的组织方式。
四、Redux:单 Store、Action 和 Reducer
Redux 与具体 UI 框架无关,可以和 React、Vue、Angular 或原生 JavaScript 配合。它的历史核心模型是:
View -> dispatch(action) -> reducer(state, action)
-> new state -> subscribe/render View

1. Store
经典 Redux Store 提供三个主要方法:
getState():读取当前 state;dispatch(action):分发 action;subscribe(listener):订阅 state 变化。
Redux 核心要求通过 dispatch 触发更新,不能直接修改 Store 内部 state。现代 Redux 项目通常使用 Redux Toolkit 的 configureStore,不建议手写底层初始化:
import { configureStore, createSlice } from '@reduxjs/toolkit'
export const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
increment(state) {
// Redux Toolkit 使用 Immer,允许写出看似可变的更新
state.value += 1
},
decrement(state) {
state.value -= 1
},
},
})
export const store = configureStore({
reducer: {
counter: counterSlice.reducer,
},
})
store.dispatch(counterSlice.actions.increment())
console.log(store.getState().counter.value)
Redux Toolkit 的 case reducer 可以写 state.value += 1,但底层仍会生成不可变的新 state。不要把这段代码理解为 Redux 核心允许业务代码直接修改外部 state。
2. Action
Action 通常是一个至少包含 type 的普通对象:
const action = {
type: 'todos/todoAdded',
payload: {
text: 'Learn Redux',
},
}
Action 描述“发生了什么”,不应该直接保存需要执行的 UI 操作。Redux Toolkit 的 createSlice 会自动生成 action creator 和 action type。
3. Reducer
Reducer 是接收 (previousState, action) 并返回下一个 state 的函数:
function counterReducer(state = { value: 0 }, action) {
switch (action.type) {
case 'counter/incremented':
return { value: state.value + 1 }
case 'counter/decremented':
return { value: state.value - 1 }
default:
return state
}
}
传统 Redux reducer 需要满足:
- 对相同输入得到相同输出;
- 不修改传入的 state;
- 不执行网络请求、随机数、时间读取等不可控副作用;
- 不认识的 action 返回原 state;
- 状态没有变化时尽量返回原引用,便于订阅者判断。
Redux Toolkit 通过 Immer 降低不可变更新的书写成本,但 reducer 仍应保持纯粹。异步请求应放在 thunk、middleware、listener middleware、RTK Query 或其他明确的副作用层。
4. 一个用于学习的 createStore
下面的实现只用于理解原理,缺少 Redux 正式实现中的初始化 action、错误检查、listener 快照、嵌套 dispatch 约束等,不应直接用于生产:
function createStoreForLearning(reducer) {
let state = reducer(undefined, { type: '@@init' })
let listeners = []
function getState() {
return state
}
function dispatch(action) {
state = reducer(state, action)
listeners.slice().forEach(listener => listener())
return action
}
function subscribe(listener) {
listeners.push(listener)
return () => {
listeners = listeners.filter(item => item !== listener)
}
}
return { getState, dispatch, subscribe }
}
5. combineReducers
大型应用通常把状态拆成多个 slice reducer,再合成 root reducer:
import { combineReducers } from 'redux'
const rootReducer = combineReducers({
todos: todosReducer,
visibilityFilter: visibilityFilterReducer,
})
Redux Toolkit 的 configureStore({ reducer: { todos, users } }) 会自动完成常见组合。原文中的简化 combineReducers 只适合解释“每个 reducer 维护 state 的一部分”,不应替代 Redux 正式实现的 key 校验和状态变化检查。

五、Redux 与 Flux 的差异


可以把经典差异总结为:
| 项目 | 经典 Flux | 经典 Redux |
|---|---|---|
| Store | 通常多个 Store | 通常一个 root Store,内部拆分 reducer |
| Dispatcher | 独立 Dispatcher | store.dispatch 集成分发入口 |
| 更新 | Store 响应 action | reducer 根据 state/action 返回新 state |
| 不可变性 | 依赖实现和约定 | 传统 Redux 强调不可变更新,RTK 用 Immer 简化 |
| 副作用 | 由实现决定 | middleware/thunk/saga 等放在 reducer 外 |
| 调试 | 依赖实现 | Redux DevTools、action 日志、状态回放生态成熟 |
“Redux 只能有一个 Store”是经典架构约定,不是 JavaScript 层面无法创建多个 Store。新项目通常仍使用一个根 Store,以保持数据流和 DevTools 追踪的一致性。
六、Redux Middleware 和异步处理
Reducer 必须是纯函数,而网络请求、延时、日志、错误上报等属于副作用。Redux middleware 位于 dispatch 和 reducer 之间,典型签名是:
const logger = store => next => action => {
console.log('dispatching', action)
const result = next(action)
console.log('next state', store.getState())
return result
}
middleware 可以:
- 在 action 到达 reducer 前读取或修改它;
- 让 dispatch 接受函数、Promise 或其他自定义值;
- 在请求开始/成功/失败时分发多个普通 action;
- 统一日志、错误和取消逻辑。
Redux Toolkit 的默认方案
Redux Toolkit 的 configureStore 默认包含 redux-thunk,新项目通常使用 createAsyncThunk、RTK Query 或 listener middleware:
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
export const fetchUser = createAsyncThunk(
'users/fetchUser',
async (userId: string, thunkApi) => {
const response = await fetch(`/api/users/${userId}`, {
signal: thunkApi.signal,
})
if (!response.ok) {
throw new Error(`HTTP ${response.status}`)
}
return response.json()
},
)
createAsyncThunk 会生成 pending/fulfilled/rejected 生命周期 action,并提供 requestId、abort signal 等能力。它比手动拼接每个请求 action 更不容易漏掉 loading/error 分支。
Redux Thunk(历史与当前)
Thunk 允许 dispatch 一个函数,由 middleware 注入 dispatch 和 getState:
const fetchData = id => async (dispatch, getState) => {
dispatch({ type: 'data/fetchStarted', payload: id })
try {
const response = await fetch(`/api/data/${id}`)
if (!response.ok) throw new Error(`HTTP ${response.status}`)
const data = await response.json()
dispatch({ type: 'data/fetchSucceeded', payload: data })
} catch (error) {
dispatch({ type: 'data/fetchFailed', error: String(error) })
}
}
Thunk 自由度高,但请求开始、成功、失败的 action 和竞态处理需要业务自己设计。RTK 的 createAsyncThunk 是官方推荐的标准化封装。
Redux Promise(第三方历史方案)
redux-promise 等第三方 middleware 可以识别 Promise payload,并约定成功/失败 action。它不是 Redux 核心 API,也不是当前 Redux 官方默认方案。采用它时要核对项目依赖维护状态、错误 action 格式和取消请求语义,不能把“Promise 自动 dispatch”写成 Redux 原生能力。
七、Redux-Saga:用 Generator 描述副作用
Redux-Saga 是 Redux 的第三方 side-effect middleware,使用 Generator 和 effect 描述异步流程。它不是 Vue 的状态管理库,也不是 Redux Toolkit 的必需依赖。
原文用 Generator 说明“暂停和恢复”:
function* helloWorldGenerator() {
yield 'hello'
yield 'world'
return 'ending'
}
const iterator = helloWorldGenerator()
iterator.next() // { value: 'hello', done: false }
iterator.next() // { value: 'world', done: false }
iterator.next() // { value: 'ending', done: true }
Saga middleware 并不是直接把 Promise 变成同步请求,而是解释 Generator yield 出来的 effect 描述对象,并在完成后把结果送回 Generator:
import {
call,
put,
takeLatest,
} from 'redux-saga/effects'
function* fetchUserSaga(action) {
try {
yield put({ type: 'users/fetchStarted' })
const data = yield call(fetchUser, action.payload)
yield put({ type: 'users/fetchSucceeded', payload: data })
} catch (error) {
yield put({ type: 'users/fetchFailed', error: String(error) })
}
}
function* rootSaga() {
yield takeLatest('users/fetchRequested', fetchUserSaga)
}
原文的 put(SHOW_LOADING_ACTION, { isLoading: true }) 不是常规写法;put 通常接收一个 action 对象:
yield put({
type: 'users/fetchStarted',
payload: { isLoading: true },
})
常见 effect:
take:等待指定 action;put:分发 action;call:调用函数并等待结果;fork:启动非阻塞任务;cancel:取消任务;takeEvery:每次 action 都启动任务;takeLatest:启动新任务并取消上一个 saga 任务;all:并行等待多个 effect;race:竞争多个 effect,第一个完成后结束其他任务。
现代 Redux-Saga 并行写法使用 all:
import { all, call, race, delay } from 'redux-saga/effects'
function* loadInParallel() {
const [users, repos] = yield all([
call(fetch, '/users'),
call(fetch, '/repos'),
])
const result = yield race({
posts: call(fetchPosts),
timeout: delay(3000),
})
return { users, repos, result }
}
旧版 Redux-Saga 允许直接 yield effect 数组;当前文档更常使用 all([...]),应以安装版本为准。



takeLatest 取消的是 saga task;底层 fetch 是否真正停止,取决于请求函数是否接收并使用 AbortSignal,不能把任务取消自动等同于网络连接已取消。
Redux-Saga 的优点是:
- 异步业务逻辑集中在 saga 文件;
- action 仍然可以保持普通对象;
- Generator effect 便于测试每一步的描述;
- 可以细致控制并发、取消、重试和竞争。
代价是需要学习 Generator、effect、task 生命周期和取消语义。请求逻辑简单时,RTK createAsyncThunk 或 RTK Query 通常更直接。
八、Dva:Redux + Redux-Saga 的历史封装
Dva 是面向 React 的数据流方案,建立在 Redux、redux-saga 等技术之上,并提供 model、subscription 和路由/请求相关集成。它不是 Vue 的状态管理库。
原文对 Dva 的核心理解是正确的:把 reducer、effect、subscription 和 state 按业务 model 组织在一起,减少 action/reducer/saga 文件之间的来回切换。

一个更接近 Dva 传统写法的示意:
app.model({
namespace: 'products',
state: {
list: [],
loading: false,
},
subscriptions: {
setup({ dispatch }) {
// subscription 在 model 外部 dispatch 时使用完整 namespace
dispatch({ type: 'products/query' })
},
},
effects: {
*query({ payload }, { call, put }) {
yield put({ type: 'queryStarted' })
try {
const list = yield call(fetchProducts, payload)
yield put({ type: 'querySucceeded', payload: list })
} catch (error) {
yield put({ type: 'queryFailed', error: String(error) })
}
},
},
reducers: {
queryStarted(state) {
return { ...state, loading: true }
},
querySucceeded(state, { payload }) {
return { ...state, loading: false, list: payload }
},
queryFailed(state) {
return { ...state, loading: false }
},
},
})
原文中的 subscriptions 有时写成数组,但 Dva model 常见 API 是对象;effects 中的 generator 也需要正确使用 call、put 和 action payload。具体以项目使用的 Dva 版本文档为准。

Dva 适合被当作 React/Redux-Saga 生态的历史架构学习。其官方仓库和社区活跃度不能与当前主流 React/Redux Toolkit 方案等量齐观,新项目不应仅因为原文示例就默认采用 Dva;迁移或维护旧项目时应先锁定版本、检查 release 和插件兼容性。
九、Vuex:Vue 生态中的集中式状态管理
Vuex 与 Flux/Redux 都强调集中状态和可预测更新,但它使用 Vue 的响应式系统,传统 API 将同步更新放进 mutation,将异步流程放进 action。

1. Vuex 3(Vue 2)历史用法
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 1,
},
mutations: {
increment(state) {
state.count++
},
},
actions: {
async incrementAsync({ commit }) {
await delay(300)
commit('increment')
},
},
getters: {
doubleCount: state => state.count * 2,
},
})
组件通过 this.$store.commit('increment') 提交 mutation,通过 this.$store.dispatch('incrementAsync') 分发 action。mutation 应保持同步,这样 DevTools 才能准确记录一次状态变化;网络请求、定时器等放入 action 或外部服务。
2. Vuex 4(Vue 3)用法
import { createStore } from 'vuex'
export const store = createStore({
state: () => ({
count: 1,
}),
mutations: {
increment(state) {
state.count++
},
},
actions: {
incrementAsync({ commit }) {
return new Promise(resolve => {
setTimeout(() => {
commit('increment')
resolve()
}, 300)
})
},
},
getters: {
doubleCount: state => state.count * 2,
},
})
import { createApp } from 'vue'
import App from './App.vue'
import { store } from './store'
createApp(App).use(store).mount('#app')
Vuex 4 的 API 主要是 Vuex 3 的 Vue 3 适配,不能把 new Vue({ store }) 直接当作 Vue 3 入口。Vuex 模块仍可拆分 state、getters、mutations 和 actions。
3. Vuex 的组成
- state:共享数据;
- getter:从 state 派生可复用结果;
- mutation:同步改变 state 的明确入口;
- action:处理异步或组合多个 mutation;
- module:拆分大型 Store。
原文“Vuex 的 state 不能直接改”是更新约定。Vuex 在开发环境可以通过 strict mode 检测非 mutation 修改,但 JavaScript 本身不会让对象彻底不可写。开启 strict mode 会增加深度 watch 成本,不建议生产环境无条件开启。
4. Vuex、Pinia 和版本状态
Vuex 官方文档目前把 Pinia 作为 Vue 官方状态管理的默认推荐,并说明 Vuex 3/4 仍会维护但不太可能增加新功能。Pinia 可以视作 Vuex 5 RFC 方向的独立实现,但“Vuex 5 一定会发布”或“Pinia 就是 Vuex 5 正式版本”都不严谨。
- Vuex 3:主要用于 Vue 2;
- Vuex 4:主要用于 Vue 3;
- Pinia 2:可用于 Vue 2.7/Vue 3 的旧兼容项目;
- Pinia 3:面向 Vue 3,当前新 Vue 3 项目优先考虑 Pinia;
- 不要为了新项目继续照搬 Vuex mutation/action 样板,先评估 Pinia 是否更合适。
十、React-Redux 与现代 Redux UI 绑定
Redux 本身不负责 UI 绑定。React 项目过去常使用 react-redux 的 Provider、connect、mapStateToProps 和 mapDispatchToProps:

import { Provider, useDispatch, useSelector } from 'react-redux'
import { store } from './store'
import { counterSlice } from './counterSlice'
function Counter() {
const value = useSelector(state => state.counter.value)
const dispatch = useDispatch()
return (
<button onClick={() => dispatch(counterSlice.actions.increment())}>
{value}
</button>
)
}
export default function App() {
return (
<Provider store={store}>
<Counter />
</Provider>
)
}
connect 仍可用于维护旧代码,但当前 React-Redux 文档更常使用 hooks。原文把 React-Redux 说成“React 官方出的”不准确:它是 Redux 生态的官方维护绑定库,由 Redux 组织维护,不是 React 核心包。
十一、MobX:可观察状态与反应式派生
Redux/Flux 更强调显式 action、纯 reducer 和单向流;MobX 的核心思想是:
状态变化后,读取这些状态的计算和视图自动重新运行。
依赖关系可以概括为:
observable state -> computed / reaction / observer
-> state 改变后只重新运行相关反应
原文中的 autoRun 不是 MobX 公共 API,正确名称是 autorun。MobX 6 新项目通常使用 makeAutoObservable,而不是把旧装饰器示例直接复制到 Babel/TypeScript 配置中:
import {
autorun,
makeAutoObservable,
} from 'mobx'
class CounterStore {
count = 0
user: unknown = null
constructor() {
makeAutoObservable(this)
}
get doubled() {
return this.count * 2
}
increment() {
this.count++
}
}
const store = new CounterStore()
const dispose = autorun(() => {
console.log(store.count, store.doubled)
})
store.increment()
dispose()
makeAutoObservable 会根据成员自动推断 observable、computed 和 action。异步操作完成后如果要在 action 外修改多个状态,可以使用 runInAction:
import { runInAction } from 'mobx'
async function loadUser() {
const user = await fetch('/api/user').then(response => response.json())
runInAction(() => {
store.user = user
})
}
旧装饰器写法的版本边界
原文使用:
class Store {
@observable a = 0
@action
increment() {
this.a++
}
}
这属于 MobX 早期/装饰器配置相关写法。MobX 6 仍可以在特定现代 decorators 或 legacy decorators 配置下使用装饰器,但必须明确配置和初始化方式。不要把上面的代码当作“无需配置即可运行”的当前示例。
如果不希望依赖装饰器编译配置,可以显式声明注解:
import {
action,
computed,
makeObservable,
observable,
} from 'mobx'
class Todo {
finished = false
title = ''
constructor() {
makeObservable(this, {
finished: observable,
label: computed,
toggle: action,
})
}
get label() {
return `${this.title}: ${this.finished ? 'done' : 'open'}`
}
toggle() {
this.finished = !this.finished
}
}
如果确实使用 MobX 6 的现代 Stage-3 decorators,必须开启对应的 TypeScript/Babel 配置,并使用 accessor:
import { action, computed, observable } from 'mobx'
class ModernTodo {
@observable accessor finished = false
title = ''
@computed get label() {
return `${this.title}: ${this.finished ? 'done' : 'open'}`
}
@action toggle() {
this.finished = !this.finished
}
}
MobX 与 React 常使用 mobx-react-lite 的 observer 包装函数组件;Vue 项目不应因为“MobX 可以跨框架”就自动引入它,Vue 3 通常优先使用 Pinia 或组合式状态。

十二、Redux 与 MobX 的对比

| 对比项 | Redux/Redux Toolkit | MobX |
|---|---|---|
| 核心思路 | action 描述变化,reducer 产生新 state | observable 状态驱动 computed/reaction |
| 更新风格 | 传统 Redux 偏不可变;RTK 使用 Immer 简化 | 通常在 action 中直接改变 observable |
| 数据流 | 显式、可序列化、易回放 | 隐式依赖追踪,视图更新粒度细 |
| 副作用 | thunk、listener、saga、RTK Query 等 | action、flow、reaction 或业务服务 |
| 样板量 | RTK 已显著减少传统 Redux 样板 | 通常较少,但需要理解响应式依赖 |
| 调试重点 | action 日志、时间旅行、状态快照 | observable、reaction、action 边界 |
不能简单得出“小项目用 MobX,大项目用 Redux”这样的固定结论。选择应该考虑团队经验、状态是否需要可序列化、调试和回放需求、异步数据缓存、SSR、生态和维护成本。
十三、当前 Vue 项目的选择建议
当前 Vue 3.5 项目可以按状态范围选择:
- 组件本地状态:
ref、reactive、computed; - 父子/跨层级依赖:props/emits、provide/inject;
- 多个页面共享的客户端状态:Pinia;
- 服务端数据缓存:结合请求库或专门的 query/cache 方案,不要把所有请求结果无期限塞进全局 Store;
- 维护 Vue 2 项目:Vuex 3 或 Pinia 2,按项目现状和迁移计划决定;
- React 旧项目:Redux/React-Redux、redux-thunk、redux-saga、Dva 等需按锁定版本维护;
- React 新项目:优先 Redux Toolkit + React-Redux,是否使用 RTK Query、listener middleware 或 Saga 取决于异步复杂度。
状态管理库不是越多越好。不要在一个 Vue 3 项目中同时引入 Vuex、Pinia、MobX、mitt,只为了“共享数据更灵活”;重复的数据源会带来同步、SSR 隔离和调试困难。
十四、原文中容易误解的说法
- “Redux 必须每次手写完整不可变更新”是传统 API 的体验;当前官方推荐 Redux Toolkit,Immer 会简化 case reducer。
- “Redux 的 reducer 可以处理异步”不准确;异步应在 middleware、thunk、listener、saga 或请求缓存层。
- “redux-saga 的
takeLatest一定取消 HTTP 请求”不准确;它主要取消 saga task,网络请求需要配合 AbortSignal。 - “Dva 是 Vue 的状态管理方案”错误;Dva 面向 React/Redux-Saga 生态。
- “MobX 的
autoRunAPI”错误,应为autorun。 - “MobX 装饰器代码开箱即用”过时;MobX 6 需要按 decorators 配置,推荐先考虑
makeAutoObservable。 - “Vuex 5 会按原计划发布”不应作为事实;Pinia 是官方当前新 Vue 项目推荐方案。
- “所有状态都必须放 Store”会造成过度集中;组件本地状态应留在组件。
- “middleware 就是简单包裹 dispatch”只是直观模型;正式 middleware 还要遵守
store => next => action链式传递和返回值语义。
十五、总结
原文最值得保留的主线是:
共享状态
-> 统一入口
-> 可预测更新
-> UI 订阅变化
Flux 解释单向数据流,Redux 把 action/reducer/store 约束做得更明确,middleware 负责把副作用放到 reducer 外;Vuex 将类似思想与 Vue 响应式系统结合;Redux-Saga 使用 Generator 描述复杂副作用;Dva 把 React/Redux-Saga 的多个文件按 model 聚合;MobX 则通过可观察状态和依赖追踪减少显式样板。
对当前 Vue 3.5 项目而言,优先选择最小且清晰的方案:组件状态用 Vue API,跨页面共享状态用 Pinia,服务端数据用合适的缓存层。学习 Flux、Redux、Vuex、Saga、Dva 和 MobX 的价值在于理解状态流动和副作用边界,而不是把所有库同时引入项目。
官方参考
Vue 与 Pinia/Vuex
Redux 与 Redux Toolkit
- Redux Getting Started
- Redux Fundamentals
- Redux Toolkit Getting Started
- Writing Logic with Thunks
- Redux Middleware
- React-Redux Hooks
Redux-Saga 与 Dva
MobX
原文出处
原文标题:Vuex, Flux, Redux, Redux-saga, Dva, MobX
原文来源:知乎专栏配图及文章整理。本文保留原文的历史概念和示例方向,并对抓取损坏、版本过时和错误 API 进行了修订。