Vuex是专门为vue.js开发的状态管理模式(状态就是数据),采用集中式存贮管理应用的状态;相当于把组件中的数据提升到一个全局的地方(所有的组件都能访问到),则就是vuex的store,当需要某一个组件的数据时,直接从store中获取(this.$store.state.数据名);
- Vuex的状态存储是响应式的,当vue组件从store中读取状态时,如果store的状态发生变化,相应组件也会相应更新
- 改变store中的状态的唯一途径是显式提交mutation
主要模块
- State:定义了应用状态的数据结构,可以在这里设置默认的初始状态。
- Getter:允许组件从 Store 中获取数据,mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性。
- Mutation:是唯一更改 store 中状态的方法,且必须是同步函数。
- Action:用于提交 mutation,而不是直接变更状态,可以包含任意异步操作。
- Module:允许将单一的 Store 拆分为多个 store 且同时保存在单一的状态树中。
Vuex使用步骤
按照vuex,并且配置store.js文件
2. 把需要vuex托管的数据放到state中
3. 如果state中的数据需要被修改,则创建相应的mutation
4. 如果state中的数据会被异步修改,则创建相应的action,并且在action中使用commit mutation的方式修改state里面的数据
5. 最后导出一个Vuex的Store实例,并且在创建Vue的根实例的时候配置,配置store属性以后,在组件中可以通过this.$store访问store实例
6. 在整个Vue的应用中,任何地方都能访问状态,通过this.$store.state.数据名的方式
7. 更新数据,如果是同步更新,提交mutation【this.$store.commit(mutation的名字,传给mutation的参数)】;如果是异步更新,分发action【this.$store.dispatch(action的名字,payload)】
`Vuex基本使用
获取公共状态信息:this.$store.state.xxx
- 直接调取mutation中的方法:this.$store.commit([mutation-function-name],[payload])
- 调取acttion中的方法:this.$store.dispatch([actions-function-name],[payload])
import Vue from 'vue'
import Vuex from 'vuex'
//Vuex是vue中的插件
Vue.use(Vuex);
/*vuex 中的数据是存在内存中的,一刷新就没有了*/
//创建store容器(管理数据)并且导出
//存储到store中的状态是响应式的,当store中的状态发生变更时,所有用到的状态的地方都自动更新
export default new Vuex.Store({
//state存贮公共状态(data)
state:{
b:12
},
//mutations存储sync function,这些方法改变state中的状态信息
//mutations的方法只能通过commit mutation的方法调用
mutations:{
example1(state){
//state就是上面的state对象,通过state可以修改state里面的状态
state.num++
},
example(state,payload){
//state容器中存储的状态信息
//payload是commit执行的时候传递进来的参数信息,通常是一个对象
//this.$store.commit('example',1000)
console.log(payload)
state.num+=payload.num
}
},
//actions存储async存储async function,这些方法首先异步获取需要的数据,然后在基于commit触发mutations中的方法,从而改变state
actions:{
//在actions下面的方法称为action,action中可以有异步程序,例如ajax和定时器,
//在action中更新状态,仍需要提交到mutation
asyncadd(context,payload){
//context对象上有commit方法,commit()方法可以提交mutation
//context 对象上还有dispatch方法,用来分发其他的action
//this.$store.dispatch('exampleAction','aa')
//
setTimeout(_=>{
context.commit('example',1000);
// context.commit('example1',1000);
},1000)
}
},
//getters储存的方式等价于computed计算属性,监听当前容器中的state的计算属性
getters:{
//add(state){}
}
});
//如果修改store中的数据,只要提交mutation;但是mutation函数中只能同步的程序的(修改state里面的状态不能写在异步程序中)
//异步处理在哪里:写在actions中
//如果这些数据被多处依赖了,再放到vuex中,
//vuex在项目中的应用,很多人都喜欢把数据都写在vuex中,不管是不是被多处依赖了
基于各种map简化操作方式
1. 基本语法
import {mapState,mapGetters,mapMutations,mapActions} from 'vuex';
export default {
computed:{
//=>数组方式
...mapState(['n','m']), //=>this.n
//=>对象方式
...mapState({
a:'n', //=>this.a === this.$store.state.n
}),
//=>函数方式
...mapState({
a:state=>state.xxx.xxx
})
},
//=>其余的map操作方式和mapState类似
}
module按照模块进行分组
- store.js
import Vue from 'vue';
import Vuex from 'vuex';
import logger from 'vuex/dist/logger';
import Person from './Person';
import Product from './Product';
Vue.use(Vuex);
export default new Vuex.store({
//把每一个模块中的state-actions都进行合并
//1. state会按照各版块进行区分, state={Person:{...},Product:{...},isLogin:true}
//2. getters/mutations/actions默认不会进行模块划分,默认全部合并在一起,会导致冲突,
//解决方案:每一个模块设置namespaced:true,这样在最后合并在一起的时候,会以模块的名字作为前缀,进行标识区分
// mutations={'Person/changeName':function xxx,
// 'Product/changeName':function xxx,
// changeLogin:function xxx,...
// }
modules:{
Person,
Product
},
//各个板块公共的状态和方法
state:{
isLogin:true
},
getters:{
queryLogin(state){return state.isLogin;}
},
mutations:{
changeLogin(state,payload){
changeLogin(state,payload){
state.isLogin=payload;
}
}
},
plugins: [logger()]
})
person.js
/*
* 个人中心板块中的公共状态管理
*/
export default{
namespaced:true,
state:{
name:'珠峰',
baseInfo:{
email:'121312232@qq.com',
phone:'1223232323'
}
},
getters:{
queryBase(state){
//=>state:本模块的私有状态
// console.log(state);
return `${state.name}的邮箱是:${state.baseInfo.email}`;
}
},
mutations:{
changeName(state,payload){
state.name=payload;
},
changeBase(state,payload){
state.baseInfo={
...state.baseInfo,
...payload
};
}
},
actions:{
actionDemo(context,payload){
// context.state 当前模块私有的状态
// context.rootState 整个store中的全部状态
// console.log(context, payload);
}
}
product.js
/*
* 产品板块中的公共状态管理
*/
import * as types from './store-type';
export default{
namespaced:true,
state:{
name:'就业',
baseInfo:{
time:'5 m'
}
},
getters:{
[types.PRODUCT_GETTER_QUERY_BASE](state){
return ``${state.name}课程的周期是:${state.baseInfo.time}`;
}
},
mutations:{
[types.PRODUCT_MUTATION_CHANGE_NAME](state, payload) {
state.name = payload;
}
}
}
store-types.js
//宏标识名称管理
export const PRODUCT_MUTATION_CHANGE_NAME="PRODUCT_MUTATION_CHANGE_NAME";
export const PRODUCT_GETTER_QUERY_BASE="PRODUCT_GETTER_QUERY_BASE"
获取状态或者触发mutations/actions中的方法执行
- this.$store.state.Product.js
- this.$store.dispatch(‘Product.js/xxx’)
- …mapActions(‘Product.js’,[‘xxx’])
- 基于createNamespacedHelpers处理
import {createNamespacedHelpers} from 'vuex'
let {mapActions,mapState}=createNamespacedHelpers('product.js')
...mapActions(['xxx']);
Vuex中的面试题
Vuex和单纯的全局对象有什么区别?
- Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。
为什么 Vuex 的 mutation 中不能做异步操作?
Vuex中所有的状态更新的唯一途径都是mutation,异步操作通过 Action 来提交 mutation实现
每个mutation执行完成后都会对应到一个新的状态变更,这样devtools就可以打个快照存下来,然后就可以实现 time-travel 了。如果mutation支持异步操作,就没有办法知道状态是何时更新的,无法很好的进行状态的追踪,给调试带来困难。
Vuex的action有返回值吗?返回的是什么?
store.dispatch 可以处理被触发的 action 的处理函数返回的 Promise,并且 store.dispatch 仍旧返回 Promise
- Action 通常是异步的,要知道 action 什么时候结束或者组合多个 action以处理更加复杂的异步流程,可以通过定义action时返回一个promise对象,在派发action的时候就可以通过处理返回的 Promise处理异步流程
一个 store.dispatch 在不同模块中可以触发多个 action 函数。在这种情况下,只有当所有触发函数完成后,返回的 Promise 才会执行。
为什么不直接分发mutation,而要通过分发action之后提交 mutation变更状态
- mutation 必须同步执行,我们可以在 action 内部执行异步操作
- 可以进行一系列的异步操作,并且通过提交 mutation 来记录 action 产生的副作用(即状态变更)