Vuex学习 - 理解Vuex的原理

最近在使用Vuex的时候,把Vuex和NGRX一起对比看了下,总体而言,都是对FLUX 思想的实现,不过使用起来,个人感觉vuex的使用比NGRX更舒服一些。
下面介绍一些Vuex的实现原理, 本文只是实现一个最简单的类vuex,为了有助于理解vuex的工作方式,实际vuex的实现要比这复杂的多。

Vuex实现的原理

先放代码,在分块讲解:

const Store = function Store (options = {}) {
  const {state = {}, mutations={}, getters={},actions={}} = options
  const computed = {}
  const store = this
  store.getters = {};
  for (let [key, fn] of Object.entries(getters)) {
    computed[key] = function () { return fn(store.state, store.getters); };
    Object.defineProperty(store.getters, key, {
      get: function () { return store._vm[key]; },
    });
  }
  this._vm = new Vue({
    data: {
      $$state: state
    },
    computed,
  })
  this._mutations = mutations
  this._actions = actions
}
Store.prototype.commit = function(type, payload){
  if(this._mutations[type]) {
    this._mutations[type](this.state, payload)
  }
}

Store.prototype.dispatch = function(type){
  if(this._actions[type]) {
    const store = this;
    this._actions[type]({commit:this.commit.bind(store)});
  }
}

Object.defineProperties(Store.prototype, { 
  state: { 
    get: function(){
      return this._vm._data.$$state
    } 
  }
});

Vuex数据的响应式

在Vue框架中,当你把数据定义在Data属性下的时候,里面的属性就可以做到响应式的监听,其实是通过的Proxy做的,也就是常说的

Object.defineProperty(obj, prop, value);

因此,在Vue中实现Vuex,我们完全可以应用这个想法,把你的state 放到Vue实例的data属性里:

this._vm = new Vue({
    data: {
      $$state: state
},

这里面的 state就是我们在使用Vuex中传入的state,这样在我们使用的时候,它的监听和通知就由Vue框架在实例化Vue组件的时候帮我们做好了,其实是在new Vue() 这个函数里做的(感兴趣的后面可以分开一篇来写)。

还有个问题,大家在使用的时候知道,我们是直接获得的state属性,并没有调用什么"_vm.$$state"啊什么的,这其实很简单:

Object.defineProperties(Store.prototype, { 
  state: { 
    get: function(){
      return this._vm._data.$$state
    } 
  }
});

我们只需定义下state的属性获取就可以了。

Commit的实现

Store是一个大的状态容器,(说白了可以简化成Object),那么我们规定你只能通过mutation去更改数据,并且mutation是纯函数,不含异步操作的。

Store.prototype.commit = function(type, payload){
  if(this._mutations[type]) {
    this._mutations[type](this.state, payload)
  }
}

Dispatch的实现

dispatch 通常是用来trigger action 的,那么dispatch的实现又是什么样的呢?

Store.prototype.dispatch= function(type, payload){
  if(this._actions[type]) {
    this._actions[type]({this.commit.bind(this)}, payload)
  }
}

getters的实现

大家在用getters的时候发现确实很方便,那它又是如何实现的呢?
getters其实是借用了vue的computed属性,这样它还做到缓存:

store.getters = {};
  for (let [key, fn] of Object.entries(getters)) {
    computed[key] = function () { return fn(store.state, store.getters); };
    Object.defineProperty(store.getters, key, {
      get: function () { return store._vm[key]; },
    });
  }

结合最开始的创建Vue组件,我们要把computed注册到vue组件的computed属性上:

  this._vm = new Vue({
    data: {
      $$state: state
    },
    computed,
  })

这就是 Vuex的基本实现形式,当然肯定和Vuex源码有不一样的地方,比如modules的实现,比如actions的param实际是context,等等。大家感兴趣的可以再深入去读vuex的源码。

你可能感兴趣的:(vue)