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中的方法,从而改变stateactions:{//在actions下面的方法称为action,action中可以有异步程序,例如ajax和定时器,//在action中更新状态,仍需要提交到mutationasyncadd(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 产生的副作用(即状态变更)
