本文的目的是解析vuex基本原理,并实现一个简易版本的vuex。
vuex的作用:
- 集中管理数据
- 可预测的更改数据
基本原理
- 将页面的响应式数据统一放在store的state对象里面,state里的数据不能直接更改,需要调用mutations和actions里的方法来更改
- state里的数据是可响应的,会进行依赖收集,当state里的数据改变的时候,依赖它的组件会重新渲染
- getters是计算属性,根据state计算出返回值
使用vuex的基本方式如下:
// App.vue
<template>
<div>
<p @click="$store.commit('increment')">{{$store.state.count}}</p>
<p @click="$store.dispatch('increment')">{{$store.state.count}}</p>
<p>{{$store.getters.doubleCount}}</p>
</div>
</template>
// store.js 文件
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
count: 0
},
getters: {
doubleCount: state => {
return state.count * 2;
}
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
setTimeout(() => {
context.commit('increment')
}, 1000);
}
}
});
export default store;
简易版vuex实现
我们要实现的功能列表:
- 将store实例混入到每个Vue组件中,可以在组件中使用this.$store访问到store实例
- store配置对象中的state设置为可响应的,并可以通过this.$store.state访问
- store配置对象中的getters实现计算属性功能
- 调用this.$store.commit的时候,调用store配置对象里的mutations里的对应方法
- 调用this.$store.dispatch的时候,调用store配置对象里的actions里的对应方法
实现的简易版vuex源码如下,细节都写在注释里了,可以将引入的vuex直接替换为下面的文件,即可体验上面说的这些基本功能:
let Vue;
// Store实例构造函数
class Store {
constructor(options) {
// 结构配置对象里的属性
let {state, getters, mutations, actions} = options;
// 将配置对象里的属性添加到store实例上,方便实例上的方法引用
this._mutations = mutations;
this._actions = actions;
this._getters = getters;
// getters里的属性放到computed里,使用computed来做计算属性,
// 因为getters里的方法需要传一个state参数,而computed是不需要参数的,
// 所以这里computed定义了一个没有参数的函数,再在这个函数里面调用getters里对应的函数
let computed = {};
Object.keys(getters).forEach(key => {
let fn = getters[key];
computed[key] = function() {
return fn(state);
}
})
// new 一个Vue实例,让state和computed挂在该实例上,使其响应化
this._vm = new Vue({
data: state,
computed
})
// 绑定commit、disptach上下文为store实例,这样不管如何调用commit和dispatch,里面的实例都指向store实例
this.commit = this.commit.bind(this);
this.dispatch = this.dispatch.bind(this);
}
// 当使用this.$store.getters的时候,指向_vm
get getters() {
return this._vm
}
// 当使用this.$store.state的时候,指向_vm
get state() {
return this._vm;
}
// 调用commit方法的时候,调用store配置对象里对应的mutations方法
// 参数1,type -- mutations的类型
// 参数2,payload -- 载荷
commit(type, payload) {
let entry = this._mutations[type];
entry(this.state, payload);
}
// 调用dispatch方法的时候,调用store配置对象里对应的actions方法
dispatch(type, payload) {
let entry = this._actions[type];
entry(this, payload);
}
}
// 注册插件的时候调用的方法
function install(_Vue) {
Vue = _Vue;
// 混入,为了可以在所有Vue实例中通过this.$store访问store实例
Vue.mixin({
beforeCreate() {
if (this.$options.store) {
Vue.prototype.$store = this.$options.store;
}
}
});
}
// 导出的vuex
export default {
// store构造函数
Store,
// 注册插件调用的方法
install
}