Vuex
Vuex是什么?
- Vuex 是一个专为 Vue.js(vue2) 应用程序开发的状态管理模式 + 库。
- 采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
- 状态管理模式+库
- 对组件状态的管理,方法是集中式存储
- 以对应规则保证状态以可测方式发生变化
注意:Vuex 4 支持 Vue 3,但 Vuex 主要还是为 Vue 2 设计的
为什么需要Vuex
- 通信困难: 组件之间的通信在大型项目中困难,如果他们需要频繁交互。例如很经典的父子传递(利用props和事件),如果存在多层嵌套就很复杂
- 状态混乱:如果每个组件之间通信的状态都不同,那么后期难于管理
Vuex里面有什么?
state:存储数据的地方mutations:唯一修改state的地方,是同步的,不能直接对异步任务操作actions:事件业务逻辑处理,能够执行异步函数getters:store的计算属性,方便数据调用和复用
流程
- 组件通过
dispatch向vuex发送一个actions,组件调用store.dispatch('actionName')来触发某个 action,通常用于处理异步操作或复杂的逻辑。 - 通过
actions处理完事件逻辑后将派发一个commit到mutations中,让mutations接收到要做修改的数据 mutations层获取到数据之后,修改仓库中的state状态,mutations是同步函数,负责直接修改state的数据。它接收当前state和负载数据,然后进行修改。- 组件可以通过
this.$store.state进行获取 - 而
getters层则是将state的数据进行计算,最终返回一个计算属性,这样组件就可以直接通过对应的属性进行调用,不需要this.$store.state
简化计算属性访问
mapState
- 将 Vuex 的state映射到组件的
computed属性
mapGetters
- 将Vuex的getters映射到组件的
computed属性
mapActions
- 将组件的methods映射为
store.dispatch调用
使用场景
- 多组件共享状态:如果需要多个组件共享数据状态的时候,可以采用Vuex通信,例如兄弟组件通信
- 异步操作:如果你的应用中有异步数据请求(如 API 调用),Vuex的
actions允许你管理异步操作,确保数据状态在操作完成后被正确更新 - 大型应用:在中大型应用中,组件树会变得复杂,使用Vuex可以有效管理状态,减少在组件之间传递 props 和事件的复杂性。
- 数据持久化:如果你需要在刷新之后保持状态(例如用户的登录状态),也可以结合Vuex
- 中间层观测:结合Vue Router观察路由变化(可以结合多层级实现菜单栏的动态生成)
如何使用
存在项目结构:
VueProject
src
| views
| home.vue
| srote
| index.js // 引用入口,将所有用到vuex仓库的组件都放在这里
| home
| home.js // home组件用到store
index.js
// 注意Vue3和Vue2的引用方法不同
// Vue2
import Vue from 'vue'
import Vuex from 'vuex'
import home from './home/home'
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
home,
},
})
// Vue3
import { createStore } from 'vuex'
import Home from './home/home.js'
const store = createStore({
modules: {
Home,
},
})
home.js
const state = {
count: 0,
}
// 修改state的手段
const mutations = {
COUNT(state, newCount) {
state.count = newCount
}
}
const actions = {
conputedCount({commit}, count) {
count++
commit('COUNT', count)
}
}
const getters = {
getCount(state) {
return state.count
}
}
// 前面已经通过index引入组件,所以直接暴露home组件的状态就行了
export default {
state,
mutations,
actions,
getters,
}
home.vue
<template>
<div>
<span>{{ count }}</span>
<button @click="incrementCount">Increment Count</button>
</div>
</template>
<script setup>
// 普通请求
import { computed } from 'vue'
import { useStore } from 'vuex'
const store = useStore()
// 使用 computed 来获取 Vuex 状态,存在getters计算属性,直接通过getter拿
// 如果没有就需要使用 this.$store.state.count
const count = computed(() => store.getters.getCount)
// 定义一个方法来触发 action
const incrementCount = () => {
// 与actions的方法一直
store.dispatch('computedCount', count.value)
}
// 使用mapState等方法请求
// 映射到了state
const { count } = mapState(['count'])
// 这里映射到了getter,要调用直接用getCount就可以了
const { getCount } = mapGetters(['getCount'])
const { computedCount } = mapActions(['computedCount'])
// 计算属性,使用getter
const countComputed = computed(() => getCount(store.state))
// 重新赋值 count
const nowCount = computed(() => countComputed.value)
const incrementCount = () => {
computedCount(nowCount.value) // 传递当前 count 的值,默认值从第一步拿到,是 0
}
</script>
整个过程做了什么?
普通请求
- 定义了一个总store(总仓库),并且把他暴露出去,然后把有需要用到store的组件逐个导入
- 对于home自己的仓库,对home组件的数据状态进行管理
- 定义一个home组件
- 首先拿到存放在仓库的默认值
count:0 - 当我点击button之后,派发一个叫
computedCount名称的异步函数,将拿到的默认值也穿进去 - 根据actions中的
computedCount函数对数据处理,执行count++,提交commit方法,通知mutations现在这个count要更新了 - mutations修改state中的count值
- 由于getters被用来计算并返回
count,它会获取到更新后的值 - 组件中的
count通过computed自动更新,重新渲染DOM,显示最新的count值。
- 首先拿到存放在仓库的默认值
使用对应方法请求(简化书写):
mapState:将store中的state映射到组件的computed属性中,也就是将store中的count映射到home组件中的count中mapGetters:将getCount映射 getters,使得组件可以访问计算后的值mapActions:将store的incrementaction映射为组件中的方法- 当用户点击按钮时,调用
increment方法,触发store.dispatch('increment') - 在
incrementaction 中,调用commit('INCREMENT'),提交一个 mutation mutations中的INCREMENT函数执行,更新state.count的值getters会自动重新计算并返回最新的count值- 由于组件中的
count是通过computed自动绑定到store的状态,DOM 会重新渲染,显示最新的count值
组件通信
现在组件A和组件B之间存在通信需求
- 组件A通过发送请求更新状态库,派发actions处理,将组件A的数据存在store中
- 组件B直接从store中直接拿到组件A存进去的数据,操作后更新数据,又放到store
- 组件A从新拿到组件B更新的数据
登录状态保持
初始化状态:
- 在 Vuex 的
state中,设置isLoggedIn和user的初始值。- 在应用启动时,从
localStorage或sessionStorage读取用户登录状态和信息,初始化Vuex状态。登录操作:
- 组件:用户在登录组件中输入凭据。
- 派发 Action:通过 Vuex 的
loginaction,进行 API 请求验证用户信息。- 更新 Store:成功后,使用
SET_LOGIN_STATEmutation 更新isLoggedIn和user。- 存储信息:同时,将用户信息存入
localStorage或sessionStorage,确保数据持久化。登出操作:
- 派发 Action:在组件中调用
logoutaction。- 清理状态:清除 Vuex 中的登录状态和用户信息。
- 清除存储:同时清除
localStorage或sessionStorage中的用户信息。组件之间通信:
- 组件 A:通过 Vuex 更新登录状态,派发 action,触发用户信息更新。
- 组件 B:直接从 Vuex store 中获取用户信息。
- 更新 Store:如果组件 B 修改了用户信息,更新 Vuex store,再存储到
localStorage。- 组件 A:通过 Vuex 重新获取最新的用户信息,实现数据同步。
应用刷新:
- 在应用启动时,检查
localStorage或sessionStorage中是否有用户信息。- 如果存在,则自动更新 Vuex 状态,保持用户登录状态。
Vuex与pinia的区别
以下是 Vuex 和 Pinia 的主要区别,以表格形式呈现:
| 特性 | Vuex | Pinia |
|---|---|---|
| 设计理念 | 以模块化为中心,适合大型应用 | 更加简洁,适合中小型应用 |
| API | 较为复杂,需要使用 mapState、mapGetters 等 | 直接使用 store,更加直观 |
| 状态管理 | 通过 mutations 和 actions 管理状态 | 通过 actions 直接修改状态 |
| 类型支持 | 需要额外的类型定义和支持 | 内置 TypeScript 支持 |
| 插件支持 | 插件生态丰富 | 仍在发展中 |
| 性能 | 对于大型应用可能稍显繁琐 | 更加轻量化,性能更好 |
| 状态持久化 | 需要手动实现持久化逻辑 | 内置支持持久化 |
| 热重载 | 需手动配置 | 内置热重载支持 |
| Vue 版本 | Vue 2 和 Vue 3 | Vue 3 专属 |
写在最后
Vuex能够帮助开发者更方便的管理组件中数据的流向以及状态,也能够利用其特点实现不同的功能。有什么不足或错误的地方欢迎指点。