Vue源码解析:vuex(入门版)

第一次尝试写本文,还是去年年底(2019-11-26),后来入职新公司忙的要死,也就鸽了。今天重新梳理,争取弄得清楚一些:带你读 Vuex源码。

基础使用

Vuex是什么

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式

它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

  • 集中式存储
  • 状态以可预测的方式变化,改值得走流程使用提前写好的方法。方便追溯相关方法的调用来观察状态的流转过程。

用法

用法:

  • state
  • mutations
  • actions
  • getters
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.Store({
state: {
counter: 0
},
mutations: {
add(state) {
state.counter++
}
},
actions: {
add({commit}) {
setTimeout(() => {
commit('add')
}, 1000);
}
},
getters: {
doubleCount(state){
return state.count*2
}
}
})

new Vue({
store
})

在页面中:

1
2
3
4
this.$store.commit('add'); // 同步
this.$store.dispatch('add'); // 异步
this.$store.state.counter; // state获取
this.$store.getters.doubleCounter // getters

其他用法,写了很多都删了,具体看官方文档就好了。

源码基础实现

Core核心

既然是Vue生态里的插件,使用Vue.use(Vuex),new Vuex.Store({})来初始化插件,源码结构就需要实现 install方法,也需要导出 Store

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// step1
let Vue

class Store {
constructor(options) {}
}
function install(_Vue) {
Vue = _Vue
Vue.mixin({
// 筛选 判断 添加this.$store
beforeCreate() {
if (this.$options.store) {
Vue.prototype.$store = this.$options.store
}
},
})
}

// 导出 install 和 Store
export default {
install,
Store,
}

用户会传入 statemutationsactionsgettter等配置对象。

state

先来实现 state ,用户可以访问 state,但不能修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// step2
class Store{
constructor(options){
// 保证是响应式的,上次router使用了`Vue.util.defineReactive`
// 这里直接使用了 Vue 构造函数来保证数据是响应式的
this.config = new Vue({
data: {
// state = options.state
// 这里用了$$state
$$state = option.state
}
})
}
get state(){
return this.config._data.$$state
}
set state(val){
console.error('不能直接修改')
}
}

mutation

用户调用 this.$store.commit('add')

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Store{
constructor(options){
// ... 略过
// 找到方法集合
this._mutations = options.mutations
this.commit = this.commit.bind(this) // 时刻绑定this
}
commit(type,payload){
// 要找到对应的方法
const target = this._mutations[type]
// 找不到怎么办
if(!target){
console.log('没找到')
return;
}
target(this.state,payload)
// mutations: {
// add(state) {
// state.counter++
// }
// }
},

}
}

action

处理异步,和commit区别不大。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Store{
constructor(options){
this._actions = options.actions
this.dispatch = this.dispatch.bind(this)
}
dispatch(type, payload) {
const entry = this._actions[type]
if (!entry) {
console.error("未知action类型")
return
}

// 把整个 this 放进去
entry(this, payload)
// actions: {
// add({commit}) {
// setTimeout(() => {
// commit('add')
// }, 1000);
// }
// }
},
}
}

getter

getter是一个快捷选项,类似 computed

官方在 resetStoreVM做了说明

1
2
3
4
5
6
7
8
9
10
11
12
class Store{
constructor(options){
this._xGetter = options.getters
this.xGetter = this.xGetter.bind(this)
}
xGetter(type){
this.getters = {} // 定义对象

const target = this._xGetter[type]

}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Store {
constructor(opitons){
this.xGetters(options.getters)
}
xGetters(types){
this.getters={}
Object.keys(types).forEach(key=>{
Object.defineProperty(this.getters,key,{
get:()=>{
return types[key](this.state)
}
})
})
}
}

wrapgetters

请我喝杯咖啡吧~