一、Vue 的状态管理
Vue 的状态管理方案主要有 Vuex (Vue2 主流)和 Pinia(Vue3 官方推荐,Vuex 的继任者),用于管理组件间共享的状态(如用户信息、全局配置等)。
1. Vuex(适用于 Vue2)
核心概念:
State
:存储全局状态的对象(唯一数据源)。Mutation
:修改状态的唯一方式(同步操作),必须是纯函数。Action
:处理异步操作(如接口请求),通过提交Mutation
修改状态。Getter
:类似计算属性,用于派生状态(可缓存结果)。Module
:将 store 拆分为多个模块(避免单一状态树过于庞大)。
使用步骤 :
① 安装:npm install vuex --save
② 创建 store(src/store/index.js
)
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
// 状态
state: {
count: 0,
user: null
},
// 同步修改状态
mutations: {
increment(state) {
state.count++
},
setUser(state, userInfo) {
state.user = userInfo
}
},
// 异步操作
actions: {
// 模拟异步请求用户信息
fetchUser({ commit }) {
return new Promise(resolve => {
setTimeout(() => {
const user = { name: '张三', age: 20 }
commit('setUser', user) // 提交 mutation 修改状态
resolve(user)
}, 1000)
})
}
},
// 派生状态
getters: {
doubleCount(state) {
return state.count * 2
}
}
})
export default store
③ 在 main.js 中挂载:
import Vue from 'vue'
import App from './App.vue'
import store from './store'
new Vue({
store, // 挂载后可通过 this.$store 访问
render: h => h(App)
}).$mount('#app')
④ 在组件中使用:
<template>
<div>
<p>计数:{{ $store.state.count }}</p>
<p>翻倍计数:{{ $store.getters.doubleCount }}</p>
<button @click="handleIncrement">+1</button>
<button @click="handleFetchUser">获取用户</button>
</div>
</template>
<script>
export default {
methods: {
handleIncrement() {
this.$store.commit('increment') // 调用 mutation
},
async handleFetchUser() {
await this.$store.dispatch('fetchUser') // 调用 action
console.log(this.$store.state.user) // { name: '张三', ... }
}
}
}
</script>
2. Pinia(适用于 Vue3,推荐)
Pinia 简化了 Vuex 的设计(移除 Mutation
,支持 Vue3 的 Composition API),更轻量、易上手。
核心概念:
State
:存储状态(可直接修改,无需 mutation)。Action
:支持同步 / 异步操作,直接修改 state。Getter
:派生状态(同 Vuex)。
使用步骤 :
① 安装:npm install pinia --save
② 创建 store(src/store/index.js
)
import { defineStore } from 'pinia'
// 定义 store(id 需唯一)
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0,
user: null
}),
getters: {
doubleCount: (state) => state.count * 2
},
actions: {
increment() {
this.count++ // 直接修改 state
},
async fetchUser() {
// 模拟异步请求
const user = await new Promise(resolve => {
setTimeout(() => resolve({ name: '李四', age: 22 }), 1000)
})
this.user = user // 直接修改 state
}
}
})
③ 在 main.js 中挂载:
import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from 'pinia'
const app = createApp(App)
app.use(createPinia()) // 挂载 Pinia
app.mount('#app')
④ 在组件中使用(支持 Options API 和 Composition API):
<template>
<div>
<p>计数:{{ counterStore.count }}</p>
<p>翻倍计数:{{ counterStore.doubleCount }}</p>
<button @click="counterStore.increment">+1</button>
<button @click="counterStore.fetchUser">获取用户</button>
</div>
</template>
<script setup>
import { useCounterStore } from './store'
const counterStore = useCounterStore() // 引入 store
</script>
二、React 的状态管理
React 本身没有官方状态管理库,需依赖第三方工具。主流方案有:Redux (经典)、Redux Toolkit (Redux 简化版)、Context + useReducer (轻量场景),以及 Zustand 、Recoil 等新兴库。
1. Redux Toolkit(推荐,简化 Redux 用法)
Redux 核心是 "单一状态树",通过 Action
(描述操作)和 Reducer
(处理状态变更)管理状态。Redux Toolkit 简化了 Redux 的模板代码。
核心概念:
Store
:存储全局状态的容器(唯一)。Slice
:包含state
、reducer
和action
的独立模块。Action
:描述 "要做什么" 的普通对象(由createSlice
自动生成)。Reducer
:根据 action 处理状态变更的纯函数。
使用步骤 :
① 安装:npm install @reduxjs/toolkit react-redux --save
② 创建 slice(src/store/counterSlice.js
)
import { createSlice } from '@reduxjs/toolkit'
// 初始状态
const initialState = {
count: 0,
user: null
}
// 创建 slice(自动生成 action 和 reducer)
const counterSlice = createSlice({
name: 'counter', // 模块名
initialState,
reducers: {
// 同步修改
increment: (state) => {
state.count++ // Redux Toolkit 内部使用 Immer 库,支持"直接修改"写法
},
setUser: (state, action) => {
state.user = action.payload // action.payload 为传入的参数
}
},
// 处理异步 action(需配合 createAsyncThunk)
extraReducers: (builder) => {
builder
.addCase(fetchUser.pending, (state) => {
state.loading = true
})
.addCase(fetchUser.fulfilled, (state, action) => {
state.user = action.payload
state.loading = false
})
}
})
// 导出同步 action
export const { increment, setUser } = counterSlice.actions
// 定义异步 action(使用 createAsyncThunk)
import { createAsyncThunk } from '@reduxjs/toolkit'
export const fetchUser = createAsyncThunk(
'user/fetch', // action 类型名
async () => {
// 模拟接口请求
const res = await new Promise(resolve => {
setTimeout(() => resolve({ name: '王五', age: 25 }), 1000)
})
return res
}
)
// 导出 reducer
export default counterSlice.reducer
③ 创建 store(src/store/index.js
):
import { configureStore } from '@reduxjs/toolkit'
import counterReducer from './counterSlice'
// 配置 store(自动集成中间件,无需手动配置)
export const store = configureStore({
reducer: {
counter: counterReducer // 注册 slice 的 reducer
}
})
④ 在入口文件挂载(src/index.js
):
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import { Provider } from 'react-redux' // 提供 store 上下文
import { store } from './store'
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(
<Provider store={store}>
<App />
</Provider>
)
⑤ 在组件中使用:
import React, { useEffect } from 'react'
import { useSelector, useDispatch } from 'react-redux' // hooks 访问 store
import { increment, fetchUser } from './store/counterSlice'
function Counter() {
// 获取状态
const { count, user } = useSelector(state => state.counter)
// 获取 dispatch 方法
const dispatch = useDispatch()
return (
<div>
<p>计数:{count}</p>
<button onClick={() => dispatch(increment())}>+1</button>
<button onClick={() => dispatch(fetchUser())}>获取用户</button>
{user && <p>用户:{user.name}</p>}
</div>
)
}
export default Counter
2. Context + useReducer(轻量场景)
对于简单项目,可使用 React 内置的 Context
和 useReducer
实现状态管理,无需引入第三方库。
import React, { createContext, useReducer, useContext } from 'react'
// 1. 创建 Context
const CounterContext = createContext()
// 2. 定义 reducer(处理状态变更)
function reducer(state, action) {
switch (action.type) {
case 'INCREMENT':
return { ...state, count: state.count + 1 }
case 'SET_USER':
return { ...state, user: action.payload }
default:
return state
}
}
// 3. 创建 Provider 组件(提供状态和 dispatch)
export function CounterProvider({ children }) {
const [state, dispatch] = useReducer(reducer, { count: 0, user: null })
return (
<CounterContext.Provider value={{ state, dispatch }}>
{children}
</CounterContext.Provider>
)
}
// 4. 自定义 hook 简化使用
function useCounter() {
return useContext(CounterContext)
}
// 5. 在组件中使用
function Counter() {
const { state, dispatch } = useCounter()
return (
<div>
<p>计数:{state.count}</p>
<button onClick={() => dispatch({ type: 'INCREMENT' })}>+1</button>
</div>
)
}
// 6. 在入口组件中包裹
function App() {
return (
<CounterProvider>
<Counter />
</CounterProvider>
)
}
三、UniApp 的状态管理
UniApp 基于 Vue 语法,因此状态管理方案与 Vue 高度兼容,主流方案有:
- Vuex/Pinia:同 Vue 的使用方式(推荐,适合复杂项目)。
- 全局变量 :通过
getApp().globalData
定义全局变量(适合简单场景)。 - 事件总线 :通过
uni.$on
/uni.$emit
实现组件通信(适合跨组件消息传递)。
1. Vuex(UniApp 中最常用)
使用方式与 Vue2 中的 Vuex 一致,仅需注意 UniApp 的项目结构。
使用步骤 :
① 在项目根目录创建 store
文件夹,新建 index.js
:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
token: '',
userInfo: null
},
mutations: {
setToken(state, token) {
state.token = token
// 可同步到本地存储(持久化)
uni.setStorageSync('token', token)
}
},
actions: {
login({ commit }, userData) {
// 模拟登录接口
return new Promise(resolve => {
setTimeout(() => {
const token = 'xxx-token-xxx'
commit('setToken', token)
resolve(token)
}, 1000)
})
}
}
})
export default store
② 在 main.js
中挂载:
import Vue from 'vue'
import App from './App'
import store from './store'
Vue.prototype.$store = store // 挂载到 Vue 原型
const app = new Vue({
...App,
store
})
app.$mount()
③ 在页面 / 组件中使用:
<template>
<view>
<button @click="handleLogin">登录</button>
</view>
</template>
<script>
export default {
methods: {
async handleLogin() {
const token = await this.$store.dispatch('login', { username: 'test' })
console.log('登录成功,token:', token)
console.log('全局状态中的 token:', this.$store.state.token)
}
}
}
</script>
2. 全局变量(简单场景)
通过 getApp().globalData
定义全局变量,适合无需复杂逻辑的简单状态。
示例 :
① 在 App.vue
中定义:
onLaunch() {
// 初始化全局数据
getApp().globalData = {
theme: 'light',
version: '1.0.0'
}
}
② 在页面中使用:
<template>
<view>当前主题:{{ theme }}</view>
</template>
<script>
export default {
data() {
return {
theme: ''
}
},
onLoad() {
// 读取全局变量
this.theme = getApp().globalData.theme
// 修改全局变量
getApp().globalData.theme = 'dark'
}
}
</script>
总结
- Vue:Vue2 用 Vuex,Vue3 推荐 Pinia(更简洁,支持 Composition API)。
- React:复杂项目用 Redux Toolkit,简单项目用 Context + useReducer。
- UniApp:优先使用 Vuex/Pinia(与 Vue 生态一致),简单场景可用全局变量或事件总线。
状态管理的核心是 "集中管理共享状态",选择方案时需根据项目复杂度和团队熟悉度决定。