序言
最近在学习vuex,这里整理了vuex的基本概念、基本用法以及关于vuex的调试相关的知识点,来跟大家交流交流,请大家多多指教~_~
官方链接护体: vuex.vuejs.org/zh/guide/
通过阅读本篇文章,你将收获 ==>
- vuex的基本概念
- 实战中的基本用法
- 使用 vue-devtools 对Vuex 进行调试
这里提供了一个纯净的 Vuex购物车的 demo,对于想要掌握Vuex的小伙伴值得一试!!
基本概念
vuex是什么?[官链] Vuex是一个专门针对Vue应用开发的状态管理库, 结合Vue的数据响应式机制,可以进行高效状态更新。
什么时候使用Vuex?
当你需要多组件维护同一状态 或不同组件的行为都会改变同一状态时,这时如果感觉到组件间的传值开始变得复杂、混乱时,建议使用 Vuex 来将这些状态进行统一管理。
如果并不是很复杂,可以使用简易的Store来管理(创建一个Store对象,与Vue组件中的data绑定,这样状态也会是响应式的)。
核心
Vuex使用集中式存储状态,在 State中定义存储状态的数据对象,当我们需要使用状态时可以通过 store.state.name 来访问,当我们需要改变状态时,可以通过Mutation 进行修改,在Vuex中并不推荐直接修改 store.state中的数据,而是推荐 提交Mutation的方式。
在 开启
严格模式后 直接修改store.state中的数据会报错(但并不影响修改结果)
Store对象
// Vuex Store 的基本结构
const store = new Vuex.Store({
state: { // 状态存储
age: 20, name: 'Lisa'
},
mutations: { // 修改 状态的 Mutation 方法
setAge(state,payload){
state.age = payload
}
},
getters: {
student(state) {
const {age,name} = state;
return `${name}:${age}`
}
},
actions:{
setAgeAsync(store,payload){
setTimeout(() => {
store.commit('setAge',payload)
},0)
}
},
modules:{},
})
State
存储状态的数据源对象,(经过new Vuex.Store()后)变为响应式的对象,所以在初始化之前必要要将 State 的结构先写好。因为在 new Vuex.Store 的过程中,将 使用 Vue.observeble(state) 将数据进行响应式处理。
如果需要动态的 添加向 State 中添加新的属性,可以使用 Vue.set(state,key,value)
如何访问状态?
属性访问其实就是通过 store.state 进行访问,在Vue组件中,因为 在Vue.use(Vuex) 中通过 调用Vuex.install方法已经在 beforeCreate钩子中将 store对象 挂载到Vue的原型上了。
所以可以直接使用 this.$store.state.age // 获取 age 属性
Mutation
用于修改 Store 中的状态,而且在 Mutation 中不能进行异步操作
修改状态
调用 store.commit(type,payload) 来提交 Mutation ,在 Mutation 函数中 接收 (state,payload) 作为参数,commit 通过 type 来找到 对应的 Mutation,并将 附带的 payload(载荷)传入 Mutation 中
- store.commit(type,payload)
- store.commit({type , ....}) 参数对象的情况
// store 中定义 Mutaion
const store = {
...
state: {age: 2, name: 'Lisa'},
mutations: {
// 定义 Mutation, commit 的第二个参数 将作为 payload 传入
setAge(state,payload){
state.age = payload;
},
// 当commit传入对象时,载荷的也就是对象
setName(state,payload){
state.name = payload.name;
},
}
...
}
// 组件中提交 Mutation
created() {
this.$store.commit('setAge',20); //
this.$store.state.age;// age => 20
// 传入对象的方式,type 必传
store.commit({type: 'setName', name: 'David'});
}
Getters
类似Vue中的计算属性, getter 中的返回值会被缓存起来,只有当它的依赖值发生变化后才会被重新计算。
注意: 当 getter 返回的是一个函数时,值将不会被缓存,每次被访问时都会重新执行一遍, Getters 在 初始化时 会遍历所有的getter 然后使用 Object.defineProperty 拦截
get方法,在访问时 get 方法将执行 getter 方法并返回结果。
- getter 的第一个参数是 state ,第二个参数是 getters
- getter 可以利用闭包机制 返回一个函数
{
...
state: {
count: 10 ,colors: ['blue','red']
},
// 定义 getter
getters: {
totalPrice: (state)=> {
return state.count * 12
},
// 接收 getters 作为参数
length: (state,getters) => {
return getters.totalPrice.toString().length;
},
getColorIndex(state) {
return (color) => {
return state.colors.indexOf(color)
}
}
}
...
}
// 访问 getter 属性
created() {
// 直接访问
this.$store.getters.totalPrice; // 总价 => 120
// 访问接收 getters 作为参数的
this.$store.getters.length; // 3
// 调用 方法
this.$store.getters.getColorIndex('blue'); // 0
}
Actions
Actions 跟 Mutation 有些类似,不同的是:
- Actions 可以进行异步操作
- Actions 函数的第一个参数 接收的是 store
可以在 Actions 中进行异步操作后 提交 Mutation,还可以根据 store 获取 State 和 Getters , 使用store.dispath(type,payload) 提交Action
{
...
state: {
age: 12
},
mutations: {
setAge(state,payload) {
state.age = payload
}
},
actions: {
setAgeAsync(store,payload) {
// 异步操作
setTimeout(() => {
// 提交 Mutation
store.commit('setAge',payload)
},0)
}
}
...
}
... 使用
store.dispath('setAgeAsync',20); // store.state.age => 20
Modules
Vuex 允许将 一个大的整体拆分成多个细小的模块,每个模块都拥有自己的 state、getters、mutation、actions 和 嵌套子模块。
const moduleA = {
namespaced: process.env
state: () => ({ ... }),
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
namespaced
不开启的异常情况:
- mutation 同名会被同时执行
- getters 同名将会报错
当没有开启命名空间的时候,如果存在相同的 mutation 于子模块与主模块,进行 commit 时,会被同时执行。
因为当Vuex发现有同名的 mutation时会将其存到到一个数组当中
在子模块中开启 namespaced: true 后将消除这个副作用,commit 互不影响
实战中的基本用法
一般来说我们的状态是在Vue组件中使用, 使用 mapStates\mapGetters\mapMutations\mapActions 配合 Vue中的 computed 和 methods 可以极大的简化使用。
安装 & 基本使用
如果直接使用 vue cli ,可以通过选项直接创建
yarn add vuex
|--store
|--index.js
|--main.js
|--package.json
...
store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex); //先进行注册,或者调用Vuex.install 方法
const store = new Vuex.Store({
state: {
count: 12
},
getters: {
totalPrice(state) {
return state.count * 10
}
},
mutations:{
setCount(state,count){
state.count = count;
}
},
actions: {
setCountAsync(store,count){
setTimeout(() => {
store.commit('setCount',count)
},0)
}
},
modules: [],// 模块
})
export default store;
main.js
import Store from './store';
...
// 在 vue中的配置选项中注入,在beforeCreate钩子触发时,将其挂载到Vue原型上
new Vue({
...
store
...
})
使用映射简化使用
- 映射时第一个参数传入
数组: 数组中的元素为需要展开的元素,如 mapState(['age','name']) 表示要展开 age 和 name 属性 - 映射时第一个参数传入
对象: 要将对象的属性名作为 新创建的方法名,值为 字段所对应的 状态,如: mapState({age2: 'age'}), 表示将 age2 作为新方法的属性名
如何映射模块中的 State | Mutation ??
在映射方法的第一个参数 传入 要映射的 模块名称,要展开的数据放到第二个参数即可,例如:
mapState('moduleA',{age3: 'age'}),// 从 moduleA 模块取出 age
demo
import {mapState, mapGetters,mapMutations,mapActions} from 'vuex';
...
{
computed: {
...mapState(['age','name']),
...mapState({age2: 'age'}), // 对象可以进行重命名
...mapState('moduleA',{age3: 'age'}),// 从 moduleA 模块取出 age
...mapGetters(['totalPrice']),
},
methods: {
...mapMutations(['setAge']),
...mapActions(['setAgeAsync'])
}
}
// 经过映射后会变成这样
{
computed: {
age: () => this.$store.state.age ,
name: () => this.$store.state.name,
totalPrice: () => this.$store.getters.totalPrice
},
methods: {
setAge(payload){
this.$store.commit('setAge',payload)
},
setAgeAsync(payload){
this.$store.dispath('setAgeAsync',payload)
}
}
}
插件
在插件中 会暴露每次 mutation 的钩子 ,我们可以根据这个特性在 每次 mutation 结束后 执行一些操作。
结合 localStorage
当我们有一些状态需要持久化存储时,就需要使用到 localStorage 将数据存到浏览器中。
// 每次 提交 mutation 后 都会重新将 cart 数据设置到本地存储中
const localPlugin = (store) => {
store.subscribe((mutation,state) => {
if(mutation.type.startsWith('cart/')){
localStorage.setItem('cart',JSON.stringify(state.cart);
}
})
}
//
const store = {
state: {cart: JSON.parse(localStorage.getItem('cart'))},
plugins: [localPlugin],
}
内置的 Logger
Vuex 自带的插件,可以对 mutation 进行监控
使用 vue-devtools 对 Vuex 进行调试
vue-devtools是谷歌浏览器的一款插件,需要先进行下载并安装
结合 vue-devtool 工具,提供了很方便的调试模式