Vuex 是 Vue.js 中的状态管理模式,广泛应用于 Vue 2 和 Vue 3 中,其内部实现存在一些差异。
1. 什么是 Vuex ?
Vuex 是 Vue.js 官方提供的状态管理库,用于集中管理应用的所有组件的状态。主要是通过一种集中化的方式来管理共享状态,尤其适用于中大型应用,避免了复杂的组件间通信问题(如 props 和 events)。Vuex 基于 Flux 架构,使用了单向数据流。它能够确保状态的变化是可预测的,从而提高了代码的可维护性。
1.1 Vuex 的核心概念
- State:应用的状态,存储数据。
- Getters:计算属性,派发获取应用状态的逻辑。
- Mutations:同步修改状态的方法。
- Actions:包含异步操作修改状态的方法。
- Modules:模块化的 Vuex 状态管理,每个模块都有自己的 state、mutations、actions 和 getters。
2. Vuex 在 Vue 2 中的使用
2.1 Vuex 的安装与配置
在 Vue 2 中使用 Vuex,首先需要安装 Vuex:
npm install vuex@3
然后在 Vue 根实例中引入并配置 Vuex:
// main.js
import Vue from 'vue'
import App from './App.vue'
import store from './store' // 引入 store
new Vue({
render: h => h(App),
store // 确保这里注入了 Vuex store
}).$mount('#app')
2.2 Vuex 核心概念与模块
1、State
state 用于存储应用的状态。状态是集中管理的,不同组件间的共享数据都存放在 Vuex 的 state 中。
2、Getters
getters 用于从 state 中派生出一些计算值。
3、Mutations
mutations 用于同步直接修改 state。Mutation 是唯一可以直接修改 state 的方式。
4、Actions
actions 用于处理异步操作,并通过 commit 提交 mutations 来改变 state。
2.3 具体示例 🌰
目录结构
src/
├── assets/
├── components/
├── store/
│ ├── index.ts // Vuex store 的入口文件
│ └── modules/
│ └── cart.ts // 用于管理购物车的模块
├── App.vue
└── main.ts
1、cart.js 定义 Vuex 模块
// store/modules/cart.js
const cart = {
namespaced: true, // 启用命名空间
state: {
items: []
},
getters: {
// 获取购物车中的商品总数
itemCount(state) {
return state.items.reduce((count, item) => count + item.quantity, 0)
},
// 计算购物车中的总价
totalPrice(state) {
return state.items.reduce((total, item) => total + item.price * item.quantity, 0)
}
},
mutations: {
// 添加商品到购物车
addItem(state, item) {
const existingItem = state.items.find(i => i.id === item.id)
if (existingItem) {
existingItem.quantity += item.quantity
} else {
state.items.push(item)
}
},
// 删除购物车中的商品
removeItem(state, itemId) {
state.items = state.items.filter(item => item.id !== itemId)
},
// 更新商品的数量
updateItemQuantity(state, { itemId, quantity }) {
const item = state.items.find(item => item.id === itemId)
if (item) {
item.quantity = quantity
}
}
},
actions: {
// 异步添加商品到购物车
addItemAsync({ commit }, item) {
setTimeout(() => {
commit('addItem', item)
}, 1000)
},
// 异步删除商品
removeItemAsync({ commit }, itemId) {
setTimeout(() => {
commit('removeItem', itemId)
}, 1000)
}
}
}
export default cart
2、store/index.js 注册 Vuex 模块
// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import cart from './modules/cart' // 导入 cart 模块
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
cart // 注册 cart 模块
}
})
3、在 App.vue 中使用 Vuex
<template>
<div id="app">
<h1>购物车</h1>
<div>
<p>购物车商品总数:{
{ itemCount }}</p>
<p>购物车总价:{
{ totalPrice }} 元</p>
</div>
<div>
<button @click="addItemToCart">添加商品</button>
<button @click="removeItemFromCart">删除商品</button>
</div>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex'
export default {
computed: {
// 使用命名空间,映射 cart 模块的状态
...mapState('cart', ['items']),
itemCount() {
return this.$store.getters['cart/itemCount'] // 获取购物车商品总数
},
totalPrice() {
return this.$store.getters['cart/totalPrice'] // 获取购物车总价
}
},
methods: {
...mapActions('cart', ['addItemAsync', 'removeItemAsync']), // action 方法映射
addItemToCart() {
const newItem = { id: 1, name: '商品A', price: 100, quantity: 1 }
this.addItemAsync(newItem)
},
removeItemFromCart() {
this.removeItemAsync(1)
}
}
}
</script>
页面展示为:
3. Vuex 在 Vue 3 中的改进
Vuex 的状态更新是响应式的,更新后的状态会自动反映到视图中。
3.1 Vue 3 新特性对 Vuex 的影响
Vue 3 引入了许多新特性,如 Composition API,这些特性对 Vuex 的使用方式产生了一定的影响。Vue 3 强调逻辑的组合性和函数式编程,因此许多开发者希望在 Vue 3 中能够采用更灵活的状态管理方案。
Vuex 4.0 版本的更新
Vue 3 发布后,Vuex 也做了相应的版本更新,即 Vuex 4.x。Vuex 4.x 是专门为 Vue 3 提供的版本,主要改进和新增了以下几个方面:
- 支持 Vue 3 的响应式系统:Vuex 4.x 能够与 Vue 3 的响应式系统更好地结合。通过 Vue 3 的 reactive、ref 等 API,Vuex 更加高效。
- 使用 Composition API 的支持:Vuex 4.x 可以和 Vue 3 的 Composition API 一起使用,为开发者提供了更灵活的状态管理方法。
3.2 Vuex 的安装与配置
在 Vue 3 中使用 Vuex,首先需要安装 Vuex 4.x:
npm install vuex@next
然后在 Vue 根实例中引入并配置 Vuex:
import { createApp } from 'vue'
import App from './App.vue'
import store from './store' // 引入 store
createApp(App)
.use(store) // 使用 Vuex store
.mount('#app')
3.3 具体示例 🌰
延用购物车 cart 的示例
1、cart.js 定义 Vuex 模块 --- 不变
2、store/index.js 注册 Vuex 模块
// store/index.ts
import { createStore } from 'vuex'
import cart from './modules/cart'
const store = createStore({
modules: {
cart
}
})
export default store
3、在 App.vue 中使用 Vuex
Tip:store.commit 用于触发 mutation,而 mutation 是同步操作。如果需要执行异步操作,使用 store.dispatch 来触发 actions。
<template>
<div id="app">
<h1>购物车</h1>
<div>
<p>购物车商品总数:{
{ itemCount }}</p>
<p>购物车总价:{
{ totalPrice }} 元</p>
</div>
<div>
<button @click="addItemToCart">添加商品</button>
<button @click="removeItemFromCart">删除商品</button>
</div>
</div>
</template>
<script>
import { defineComponent, computed } from 'vue'
import { useStore } from 'vuex'
export default defineComponent({
setup() {
const store = useStore()
const itemCount = computed(() => store.getters['cart/itemCount'])
const totalPrice = computed(() => store.getters['cart/totalPrice'])
const addItemToCart = () => {
const newItem = { id: 1, name: '商品A', price: 100, quantity: 1 }
store.dispatch('cart/addItemAsync', newItem)
}
const removeItemFromCart = () => {
store.dispatch('cart/removeItemAsync', 1)
}
return {
itemCount,
totalPrice,
addItemToCart,
removeItemFromCart
}
}
})
</script>
页面展示:
4. Vuex 与 Vue 3 新状态管理工具 Pinia 的对比
4.1 为什么 Vue 3 引入 Pinia?
Pinia 是 Vue 3 推荐的状态管理工具,它旨在替代 Vuex,尤其是在 Vue 3 中。其设计目标是简化 API,提供更好的 TypeScript 支持,并与 Vue 3 的 Composition API 完美集成。
4.2 Vuex vs Pinia(Vue 3)对比
特性 | Vuex | Pinia |
---|---|---|
适用 Vue 版本 | Vue 2 和 Vue 3(但是 Vue 3 支持较弱) | 只支持 Vue 3 |
API 风格 | 类似于 Flux(state,mutations,actions,getters) | 现代化的 API(state,actions,getters) |
类型支持 | TypeScript 支持不完善 | 完美支持 TypeScript |
与 Vue 3 的兼容性 | 不完美,Vue 3 Composition API 集成差 | 完美兼容,支持 Vue 3 Composition API |
模块化 | 支持模块化(但需要显式声明 namespaced) | 模块化非常灵活,天然支持模块化 |
易用性 | 配置繁琐,特别是在大型项目中 | 简洁易用,API 简单直观 |
性能 | 性能不错,但对于大型应用可能较重 | 性能优化,轻量级,适合 Vue 3 环境 |
Vuex 与 Pinia 的选择建议
对于新的 Vue 3 项目,建议使用 Pinia,尤其是在需要高度类型推导和简洁 API 的场景中。对于现有的 Vue 2 项目,Vuex 仍然是推荐的选择。