簡易版Vuexソース実装

3959 ワード

Vuex使用
1、Vuexプラグインを登録する
import Vuex from 'vuex'
Vue.use(Vuex)
2、Storeインスタンスの作成
export default new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    add(state, payload) {
      state.count += payload
    } 
  },
  actions: {
    delayAdd(context, payload) {
      setTimeout(() => {
        context.commit("add", payload)
      }, 1000)
    }
  },
  getters: {
    doubleCount(state) {
      return state.count * 2
    }
  }
})
3、Vueルートインスタンスへのマウント
new Vue({
  render: h => h(App),
  store
}).$mount('#app')
4、コンポーネントでの使用
this.$store.state.count
this.$store.getters.doubleCount
this.$store.commit('add', 1)
this.$store.dispatch('')
まとめて、Vuexは以下のことをする必要があります.
  • installメソッド
  • を実装
  • Vueルートインスタンス化時に、storeオブジェクト
  • をVueルートインスタンスにマウントする.
  • store.stateとgetterはいずれもデータ応答式であり、直接変更できないstateとgetterの値はcommitとdispatch
  • のみを通過する.
  • はcommitを実現し、stateの値
  • を同期的に変更する.
  • はdispatchを実現し、stateの値
  • を非同期で修正することをサポートする.
    ソース実装
    let Vue
    class Store {
      constructor(options) {
        this._vm = null
        this._mutations = options.mutations
        this._actions = options.actions
        this._wrappedGetters = options.getters
        this.getters = {}
        const storeComputed = {}
        const self_store = this
        Object.keys(this._wrappedGetters).forEach((key) => {
          //     getters     
          const gettersFn = self_store._wrappedGetters[key]
          //    computed,              
          storeComputed[key] = () => {
            return gettersFn(self_store.state)
          }
          //   getter      ,     
          Object.defineProperty(self_store.getters, key, {
            get: () => self_store._vm[key],
            enumerable: true
          })
        })
        // new    Vue  _vm,  _vm        
        this._vm = new Vue({
          data: {
            $$state: options.state //  $$      Vue     
            // Vue              ,          
          },
          computed: {
            ...storeComputed
          }
        })
        console.log(this._vm)
      }
      get state () {
        return this._vm._data.$$state
      }
      set state(v) {
        throw new Error(`use store.replaceState() to explicit replace store state.`)
      }
      //              this  
      //     this.commit = this.commit.bind(this)   this
      commit = (type, payload) => {
        //   type   mutations        
        const fn = this._mutations[type]
        if (!fn) return
        fn.call(this, this.state, payload)
      }
      dispatch  = (type, payload) => {
        //   type   actions        
        const fn = this._actions[type]
        if (!fn) return
        fn.call(this, {commit: this.commit, state: this.state}, payload)
      }
    }
    function install(vue) {
      /* 
         1、         
         2、  vue    
         3、       ,         store  
        */
        //  1、         
        if (Store.installed) {
          return
        }
        Store.installed = true
        //2、  vue    
        Vue = vue
        //       ,         store  
        Vue.mixin({
          beforeCreate() {
            if (this.$options.store) {
              Vue.prototype.$store = this.$options.store
            }
          },
        })
    }
    export default { Store, install }
    
    ソース実装の考え方
  • installメソッドを実行する場合、Vueを通過する.mixin混入方式は、Vueをインスタンス化する際、beforeCreateライフサイクルにおいて、VueプロトタイプにstoreオブジェクトVueをマウントする.prototype.$store = store
  • Storeコンストラクション関数には、state、mutations、actions、gettersなどの
  • を取得するのに便利なインポートされた構成オプションが保存されます.
  • store.state実装:newによる新しいVueインスタンス_vm、stateを_に保存vm.data,stateは応答式データになる.stateのsetとgetを書き換え、stateの値を直接変更することを防止し、commitとdispatchでstateの値を変更するしかなく、getは_vm.data取得
  • commitメソッド実装:commitは、dispatch呼び出しがthis指向の変化であることを防止するために、thisをstoreインスタンスとしてバインドする必要がある.入力パラメータtypeによりmutationsから関数を取り出して実行し、stateパラメータ
  • に入力する
  • dispatchメソッド実装:commitメソッドと同様に、入力パラメータtypeによりactionsから関数を取り出して実行し、commitメソッドとstateをcontextに保存してパラメータとして
  • に入力する.
  • getters実装:gettersのプロパティを遍歴し、すべて_に変換vmのcomputedでは,無パラメータの高次関数を返し,Objectを用いる.definePropertyはkeyごとにgetメソッドを再定義し、setを定義する必要がなく、getterの値
  • を直接変更することを防止する.