以 Vuex 为引,一窥状态管理全貌
以下内容来自公众号逆锋起笔,关注每日干货及时送达
作者:杨成功
https://juejin.cn/post/7033682310667239460
-
什么是状态管理? -
我为什么要用 Vuex? -
组件内部状态和 Vuex 状态如何分配? -
使用 Vuex 会有哪些潜在问题?
大纲预览
-
状态与组件的诞生 -
需要状态管理吗? -
单一数据源 -
状态更新方式 -
异步更新? -
状态模块化 -
模块化的槽点 -
下一步
状态与组件的诞生
-
数据驱动视图 -
组件化
变量。在 数据驱动 这个概念出现之后,一部分变量也被赋予了特殊的含义。
-
组件层级太深,需要共享状态,此时状态要层层传递。 -
子组件更新一个状态,可能有多个父组件,兄弟组件共用,实现困难。
需要状态管理吗?
Vuex
创建 store
$ npm install --save vuex
复制代码
src/store 文件夹,在这里放所有 Vuex 相关的代码。
index.js 并写入如下代码。这段代码主要的作用就是用 Vue.use 方法加载 Vuex 这个插件,然后将配置好的 Vuex.Store 实例导出。
import Vue from 'vue'
import Vuex from 'vuex'
// 安装插件
Vue.use(Vuex)
export default new Vuex.Store({
state: {},
mutations: {},
actions: {},
modules: {}
})
复制代码
store。一个 store 中包含了存储的状态(state)和修改状态的函数(mutation)等,所有状态和相关操作都在这里定义。
import store from './store'
new Vue({
el: '#app',
store: store
})
复制代码
this.$store 访问我们导出的 store 实例。如果不挂载,直接导入使用也是一样的。
单一数据源(state)
Vuex.Store 创建了 store 实例,大家至少知道该怎么用 Vuex 了。这一步我们来看看 Vuex.Store 构造函数的具体配置。
state 配置,他的值是一个对象,用来存储状态。Vuex 使用 单一状态树 原则,将所有的状态都放在这个对象上,便于后续的状态定位和调试。
app_version 表示版本,如下:
new Vuex.Store({
state: {
app_version: '0.1.1'
}
}
复制代码
this.$store.state.app_version
复制代码
import store from '@/store' // @ 表示 src 目录
store.state.app_version
复制代码
this.$store 操作。到了非组件内,比如在请求函数中要设置某一个 Vuex 的状态,就不知道该怎么办了。
mapState 函数,它让获取多状态变得更简单。
import { mapState } from 'vuex'
export default {
computed: {
... // 其他计算属性
...mapState({
version: state => state.app_version
})
}
}
复制代码
状态更新方式(mutation)
state.app_version='xx' 这种方式修改。Vuex 规定修改状态的唯一方法是提交 mutation。
new Vuex.Store({
state: {
count: 1
},
mutations: {
increment(state, count) {
// 变更状态
state.count += count
}
}
})
复制代码
this.$store.commit('increment', 2)
复制代码
同步更新
异步更新
action 用于异步更新状态。与 mutation 不同的是,action 不直接更新状态,而是通过触发 mutation 间接更新状态。因此即便使用 action 也不违背 “修改状态的唯一方法是提交 mutation” 的原则。
new Vuex.Store({
state: {
count: 1
},
mutations: {
add(state) {
state.count++
},
reduce(state) {
state.count--
}
},
actions: {
increment(context, data) {
axios.get('**').then(res => {
if (data.iscan) {
context.commit('add')
} else {
context.commit('reduce')
}
})
}
}
})
复制代码
this.$store.dispatch('increment', { iscan: true })
复制代码
this.$store.commit 方法触发 mutation 来更新状态,完全用不到 action。
状态模块化(module)
new Vuex.Store({
modules: {
user: {
state: {
uname: 'ruims'
},
mutation: {
setName(state, name) {
state.name = name
}
}
}
}
})
复制代码
user 模块,包含了一个 state 和一个 mutation。在组件中使用方法如下:
// 访问状态
this.$store.state.user.uname
// 更新状态
this.$store.commit('setName')
复制代码
this.$store.state.[模块名称] 这种方式去访问,触发 mutation 则与全局模块一样,没有区别。
命名空间
setName 的 mutation。在组件中触发,哪个 mutation 会执行呢?
namespaced: true 的配置即可开启,如:
new Vuex.Store({
modules: {
user: {
namespaced: true,
state: {}
}
}
})
复制代码
this.$store.commit('user/setName')
复制代码
'[mutation]' 变成了 '[模块名称]/[mutation]'。
模块化的槽点
this.$store.user.state.uname
复制代码
this.$store.state.user.uname
复制代码
this.$store.commit('user/setName')
复制代码
this.$store.user.commit('setName')
复制代码
为什么吐槽
this.$store.commit 函数可以触发任何 mutation 来更改状态。如果一个组件复杂,需要操作多个子模块的状态,那么就很难快速的找出当前组件操作了哪些子模块,当然也不好做权限规定。
b, c 两个子模块的状态,不允许操作其他子模块,那么就可以先将要用到模块导入,比如这样写:
import { a, b } from this.$store
export default {
methods: {
test() {
alert(a.state.uname) // 访问状态
a.commit('setName')// 修改状态
}
}
}
复制代码
下一步
往期精彩
评论
