- 作者:老汪软件技巧
- 发表时间:2024-11-28 21:07
- 浏览量:
背景
从2019年开始使用 vue 进行前端开发,基本已经相当熟练了。但是一直有一个知识盲点就是 vuex,对这个知识点一直很抵触,中间温习过两次,但是可能因为排斥心理,到现在还是不熟悉这个知识点的用法。
近日又想搞明白这个知识点了,就认真的看了这个东西,结合项目中的用法,终于把这个知识点搞明白了,而且发现了项目中错误的 vuex 的用法。
本文记录 vuex 的基本用法及零基础学习者的疑惑。
为什么需要 vuex
vuex 是什么?下面是 vuex官方文档 的介绍:
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
以下是一个表示“单向数据流”理念的简单示意:
单项数据流的简洁性在多个组件需要共享一些公共数据时,容易遭到破坏,具体场景有:
多个视图依赖于同一状态。来自不同视图的行为需要变更同一状态。
对于问题一,传参的方法对于多层嵌套的组件将会非常繁琐,并且对于兄弟组件间的状态传递无能为力。【PS:我在项目中总结了一些组件属性传递的方法,所以没有这个困扰,此外没有兄弟组件需要传递状态的情况,这也是我至今不会 vuex 的原因。】
对于问题二,我们经常会采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。以上的这些模式非常脆弱,通常会导致无法维护的代码。【PS:真巧,这一点,我用了一种全局 js 变量的方式,也完美回避了!解决方案参考《Vue 不重新打包,动态加载全局配置的实现过程》。】
因此,我们为什么不把组件的共享状态抽取出来,以一个全局单例模式管理呢?在这种模式下,我们的组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为!
通过定义和隔离状态管理中的各种概念并通过强制规则维持视图和状态间的独立性,我们的代码将会变得更结构化且易维护。
这就是 Vuex 背后的基本思想,借鉴了 Flux、Redux 和 The Elm Architecture。与其他模式不同的是,Vuex 是专门为 Vue.js 设计的状态管理库,以利用 Vue.js 的细粒度数据响应机制来进行高效的状态更新。
核心组成
以某开源项目的定义文件为例:
import Vue from 'vue'
import Vuex from 'vuex'
import app from './modules/app'
import user from './modules/user'
import permission from './modules/permission'
import getters from './getters'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
},
actions: {
},
mutations: {
},
modules: {
app,
user,
permission
},
getters
})
export default store
从这个全局定义vuex 定义有五个核心概念组成,
vuex 原理
这个图上包含上述定义的三个属性
state:Vuex 使用单一状态树——是的,用一个对象就包含了全部的应用层级状态,这个属性定义了全局共享的状态,且是单例。actions:引发状态改变的动作,是方法定义,它调用 commit 申请提交状态改变。mutations:提交状态变更的方法定义,它可以直接操作 state 完成状态的改变。
另外两个属性的作用:
getter:有时候我们需要从 store 中的 state 中派生出一些状态,就可以定义 getter 属性,它是一类通过计算得到新值的方法。modules:由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。可以通过模块进行分割,比如上面就拆分了3个模块。使用方法
定义好 store 对象后,再创建 Vue 对象时传给它:
import store from './store'
new Vue({
el: '#app',
router,
store,
template: ' ',
components: { App }
})
然后就可以在 Vue 的其他组件中通过 this.$store 来访问 vuex 中的状态了。以我的理解主要操作有三种,而且有两种方式来操作:
操作直接方式mapXX方式
状态引用
this.$store.state.xxx
mapState['xx','xx']
提交动作
this.$mit('mutationName')
mapMutates['xx','xx']
改变状态
this.$store.dispatch(actionName)
mapAction('moduleName','actionName')
项目实践
理解了 vuex 各个部分的含义后,看了下项目中的用法,发现用的并不准确。vuex 定义的 actions 和 mutations 定义的应该是直接涉及到状态变化相关的规则。
如果某模块的 actions 定义的方法不涉及到对 state 的修改,那它就是普通的 API ,没必要封装在 vuex 中。
例如,这个获取用户分组信息的方法:
getGroupTree({ dispatch }) {
return new Promise((resolve) => {
request().then(data => resolve(data)).catch((error) => {
// TODO
});
});
}
它放在某个 store 的 module 的 acitons 定义中,但是只是一个异步请求方法,并没有通过 commit 方法改变全局 state 状态。
参考资料《辅助函数和不使用辅助函数》,这篇文章讲 vuex 的4个模块属性直接使用和用 mapXXX 使用的方法,写的非常详细的。《vuex 之 namespace 的使用》,这篇文章解答了我对命名空间的作用。当多个模块有同名的 mutations 时,调用时未指定模块名称时,namespace 属性为 true 的影响。