在看vuex源码时,有一个问题困扰着我,为什么vue当中要实例化一个Vue,即执行这段代码:
store._vm = new Vue({
data: {
?state: state
},
computed
})
我们在使用vuex时,一般是将store的state或着getters以computed的形式注入到我们的组件配置中的,那它是怎样进行依赖收集,即当store里边的属性值发生变化时是怎样触发DOM更新的??
带着这两个问题,我开始了vue源码的单步调试...
问题1: 为什么要new一个Vue,不new不行吗?
先来看一篇大佬写的vuex分析的 文章
在这篇文章里,大佬用了一个简单的例子来说明vuex的基本功能:
看完这个demo,以及这句 其实上述部分就是Vuex依赖Vue核心实现数据的“响应式化”。,我一脸懵逼,它到底是怎样依赖Vue核心实现响应式的啊啊?源码好难,我要放弃😄
然后我做个了小实验,代码如下:
const globalData = {
msg: 'Hi Vuex'
};
Vue.prototype.globalData = globalData;
const vm = new Vue({
el: '#app',
});
console.log(vm);
然后...

结果是显然的,更改globalData的属性值,页面妥妥的不会发生变化。啥原因呢??

那new一个Vue为啥就可以收集依赖了呢?在一波眼睛都快看瞎的debug操作之后,总算找到了问题的根源
function defineReactive (
obj: Object,
key: string,
val: any,
customSetter?: ?Function,
shallow?: boolean
) {
const dep = new Dep()
//...
let childOb = !shallow && observe(val)
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter () {
const value = getter ? getter.call(obj) : val
if (Dep.target) {
dep.depend()
if (childOb) {
childOb.dep.depend()
if (Array.isArray(value)) {
dependArray(value)
}
}
}
return value
},
set: function reactiveSetter (newVal) {
//...
childOb = !shallow && observe(newVal)
dep.notify()
}
})
}
最关键的地方:

const globalData = {
msg: 'Hi Vuex'
};
const defineReactive = Vue.util.defineReactive;
function walk(obj) {
Object.keys(obj).forEach(key => {
defineReactive(obj, key);
})
}
walk(globalData);
new Vue({
beforeCreate() {
this.globalData = globalData;
},
el: '#app'
})
问题2: Vuex是怎样做到store变化让Vue更新视图的?
明白第一个问题之后问题2就迎刃而解了,获取store中的数据时触发getter,将组件的渲染watcher添加到store属性dep的subs中,从而实现依赖收集,在store属性值发生变化时执行dep.notify(),遍历该subs中的watcher,执行watcher的update方法,从而实现视图更新。
