Vuex
- 专门为Vue.js开发的状态管理模式
- 他采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化
- 状态具有响应式
什么是状态管理
-
可理解为变量管理
-
简单的看成把需要多个组件共享的变量全部存储到一个对象里面
-
然后将这个对象放在顶层的Vue实例中,让其他组件可以使用
自己实现多个组件共享的对象
const shareObj = {name:'moumangtai'}
//用prototype可以给所有的组件添加一个shareObj属性
Vue.prototype.shareObj = shareObj
//调用
this.shareObj.name
//moumangtai
- 缺点是虽然可以实现共享,但是不能响应式
哪些状态可能需要多个组件共享
- 登录状态(token,用户的名称,头像,地理信息等等)
- 商品的收藏,购物车中的物品
- 等等
单界面的状态管理
-
View:数据的显示
-
State:对于单个组件来说就是data里的数据
-
Actions:view上产生的一些事件或行为
State->View->Actions->State(形成循环)
全局单例模式(大管家)
- 将共享的状态抽取出来,交给我们的vuex,同意进行管理
- 每次访问或者修改等操作都要按照规定好的方式进行
Vuex的状态管理
官方不建议组件直接修改State,而是通过mutation来修改State,这样devtools(用于跟踪是谁修改过该状态)才能跟踪到状态的改变和来源,而如果是一些异步操作,那么就需要先经过actions(异步)再到mutation(同步)
核心概念
State
- 单一状态树 Single Sourse of truth 也叫单一数据源
- 信息的分布虽然可以让结构变得清晰,也保证了信息的安全,但当我们需要用到很多不同的信息时,就需要到不同的系统去提取,就会造成效率低下,而且不方便管理,对于维护也是一个巨大的工作。
- 而在vuex里state只有一个store,将所有需要管理的信息,全部放在一个store里。方便维护和调试。
Getters
-
类似于computed
-
从store中获取一些变化后的数据(带有计算属性)
-
具有缓存
-
State是默认参数
getters:{ powerState(state){ return state.counter * state.counter; }, more11peo(state){ return state.people.filter(s => s.age >= 11) } } -
可以将getters做为参数再在getters中使用
getters:{ more11peo(state){ return state.people.filter(s => s.age >= 11) }, //将getters作为参数 more11peoLength(state, getters){ return getters.more11peo.length } } -
不定参数的使用
moreAgepeo(state){ return function(age){ return state.people.filter(s => s.age >= age) } } //<h2>{{$store.getters.moreAgepeo(10)}}</h2>
Mutations(同步操作)
-
Vuex的store状态的唯一更新方式:提交mutation
-
对mutation进行更新
this.$store.commit('') -
带参更新(传入进来的参数叫做负载(payload))
//store的mutations mutations:{ increamentCount(state, counter){ state.counter += counter } }, //js <button @click="addcount(5)">+5</button> //methods addcount(counter){ //通过commit来提交mutation从而更新store this.$store.commit('increamentCount',counter) } -
mutations的提交风格
-
commit方式
this.$store.commit('increamentCount',counter) increamentCount(state, counter){ //该方式获取到的counter是一个number state.counter += counter } -
包含type属性的对象(可以传多个参数)
this.$store.commit({ type:'increamentCount', //es6语法,这时候的couter是一个对象而不单单是一个number //获取的是整个对象 counter }) increamentCount(state, payload){ console.log(payload); //这时候获取到的是一个对象payload state.counter += payload.counter }, //log //{type: "increamentCount", counter: 5} // type: "increamentCount" // counter: 5 // __proto__: Object
-
-
如果mutations中含有异步操作,那么devtools就无法监听,跟踪不到发生的变化,虽然页面上发生了变化,但是devtools中跟踪到的数据却没有记录下来。
Actions(异步操作)
将含有异步的操作都放在Action中,但是修改数据时必须通过mutation进行提交
整体流程:component->dispatch->Action->commit->mutation
//component
changeInfo(){
this.$store.dispatch('achangeInfo')
}
//Action
actions:{
//context 上下文 当前理解为store本身
achangeInfo(context){
setTimeout(()=>{
context.commit('changeInfo')
},1000)
}
},
//mutation
changeInfo(state){
state.info.name = "asdas"
}
Modules
-
当state中数据过多时,或者你需要对state中的数据进行抽离,就在module中对state划分模块,而每个模块都可以有自己的state,getters,actions,mutations
-
当你在modules里划分好了模块,vuex会帮你合并到state里,调用时就用$store.state.模块名
-
mutations和getters不关心你是定义在模块中还是定义在state中,都可以直接调用。(保证不重名的情况下)
-
在模块中可以传递一个rootState的参数来获取原来State中的数据
Vuex的响应式
-
首先我们必须遵守一些Vuex的一些规则
-
提前在store中初始化好所需的属性
一开始定义好的属性会被加入到响应式系统中,而响应式系统会监听属性的变化,当属性发生变化时,会通知所有界面中用到该属性的地方,让界面发生刷新
-
当给state中的对象添加或删除新属性时,使用下面的方式
1. Vue.set(state.info,'键','值') 2. Vue.delete(state.info, '键')如果直接state.info['新的键'] = "新的值"那么vue就不会监听该属性的变化,就不会产生响应式
-
Vuex的组织结构
对index.js进行抽离
import Vue from 'vue'
import Vuex from 'vuex'
import mutations from './mutations'
import actions from './actions'
import getters from './getters'
import moduleA from './modules/moduleA'
Vue.use(Vuex)
const state = {
counter:100,
people:[
{name:'wqd',age:10}
],
info:{
name:'name',
age:15,
height: 180
}
}
const store = new Vuex.Store({
state,
mutations,
actions,
getters,
modules:{
a:moduleA
}
})
export default store