Vuex温故知新
一、Vuex是什么?
Vuex 是专门为vuejs框架设计的 状态管理工具,它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
1、Vuex的构成
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EMmQP2No-1588057823521)(/Users/liurongjie/dev/workspace/technique-sharing/2020/img/vuex-state.png)]
由上图可以看出主要由以下几个部分组成:
1)state
state是存储的单一状态,是存储的基本部分。
2)Getters
getters 是store的计算属性,对state进行加工运算处理派生出来的数据,与computed类似。
特点:getter返回的数据会根据它的依赖被缓存起来,只有当它的依赖值发生变化时候才会重新计算。
3)Mutations
mutations提交数据变更,调用store.commit()
方法提交变更,为同步函数。
4)Actions
actions是一个异步函数,不直接变更数据,而是通过调用store.dispatch()
提交mutions函数方式进行数据变更。
5) Module
Module 是store分割的模块,每个模块都有自己的state、getters、mutations、actions。
const moduleA = {
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 的状态
6) 辅助函数
Vuex提供了mapState、MapGetters、MapActions等辅助函数给开发在vm中处理store
demo:
mapState
# 引入
import {mapState} from 'Vuex'
# 使用
computed: mapState({
// 箭头函数
count: state => state.count,
// 这里为了能够使用this获取局部变量localCount,必须使用常规函数
countPlusLocalState (state) {
return state.count + this.localCount
}
})
2、Vuex的使用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gYJAMjDT-1588057823524)(/Users/liurongjie/dev/workspace/technique-sharing/2020/img/vuex-2.png)]
import Vuex from 'vuex';
Vue.use(Vuex); // 1. vue的插件机制,安装vuex
let store = new Vuex.Store({ // 2.实例化store,调用install方法
state,
getters,
modules,
mutations,
actions,
plugins
});
new Vue({ // 3.注入store, 挂载vue实例
store,
render: h=>h(app)
}).$mount('#app');
二、Vuex的设计思想
Vuex将数据存储到全局的store,再将store挂载到每个vue实例组件中,利用Vue.js的细粒度数据相应机制来进行高效的状态更新。
三、Vuex原理解析
1、vuex的store是如何挂载注入到组件中的呢?
1)、在vue项目中先安装vuex,核心代码如下:
import Vuex from 'vuex';
Vue.use(vuex);// vue的插件机制
2)、利用vue的插件机制,使用Vue.use(Vuex)
时,会调用Vuex的isntall方法,装载Vuex install方法如下:
export function install (_Vue) {
if (Vue && _Vue === Vue) {
if (process.env.NODE_ENV !== 'production') {
console.error(
'[vuex] already installed. Vue.use(Vuex) should be called only once.'
)
}
return
}
Vue = _Vue
applyMixin(Vue)
}
3)、applyMixin
方法使用Vue 混入机制,vue的生命周期 beforeCreate
的钩子函数前混入vuexinit方法,核心代码如下:
Vue.mixin({ beforeCreate: vuexInit });
function vuexInit () {
const options = this.$options
// store injection
if (options.store) {
this.$store = typeof options.store === 'function'
? options.store()
: options.store
} else if (options.parent && options.parent.$store) {
this.$store = options.parent.$store
}
}
分析源码,我们知道了vuex是利用vue的mixin混入机制,在beforeCreate钩子前混入vuexInit方法,vuexInit方法实现了store注入vue组件实例,并注册了vuex store的引用属性$store。store注入过程如下图所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TmyzJHx1-1588057823526)(/Users/liurongjie/dev/workspace/technique-sharing/2020/img/vuex-install.png)]
2、vuex的state和getters是如何映射到各个组件实例中响应式更新状态?
store实现的源码在src/store.js
1)、在源码中找到resetStoreVM核心方法
function resetStoreVM (store, state, hot) {
const oldVm = store._vm
// 设置 getters 属性
store.getters = {}
const wrappedGetters = store._wrappedGetters
const computed = {}
// 遍历 wrappedGetters 属性
forEachValue(wrappedGetters, (fn, key) => {
// 给 computed 对象添加属性
computed[key] = partial(fn, store)
// 重写 get 方法
// store.getters.xx 其实是访问了store._vm[xx],其中添加 computed 属性
Object.defineProperty(store.getters, key, {
get: () => store._vm[key],
enumerable: true // for local getters
})
})
const silent = Vue.config.silent
Vue.config.silent = true
// 创建Vue实例来保存state,同时让state变成响应式
// store._vm._data.$$state = store.state
store._vm = new Vue({
data: {
$$state: state
},
computed
})
Vue.config.silent = silent
// 只能通过commit方式更改状态
if (store.strict) {
enableStrictMode(store)
}
}
分析源码我们可以看出Vuex的state状态是响应式,是借助vue的data是响应式,将state存入vue实例组件的data中;Vuex的getters则是借助vue的计算属性computed实现数据实时监听。
computed计算属性监听data数据变更主要经历以下几个过程:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zgzYthag-1588057823527)(/Users/liurongjie/dev/workspace/technique-sharing/2020/img/v2-2730644102b66eef140110b814a90496_720w.png)]
总结:
Vuex是通过全局注入store对象,来实现组件间的状态共享。
by 刘荣杰
2020.04.16