手寫簡單Vuex

Vuex

Vuex 集中式存儲(chǔ)管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以可預(yù)測的方式發(fā)生變化。

核心概念

state 狀態(tài)、數(shù)據(jù) mutations 更改狀態(tài)的函數(shù) actions 異步操作
store 包含以上概念的容器

狀態(tài) - state

state保存應(yīng)用狀態(tài)

export default new Vuex.Store({
 state: { counter:0 },
})

狀態(tài)變更 - mutations

mutations用于修改狀態(tài),store.js

export default new Vuex.Store({
 mutations: {
   add(state) {
     state.counter++
} }
})

派生狀態(tài) - getters

從state派生出新狀態(tài),類似計(jì)算屬性

 
export default new Vuex.Store({
  getters: {
doubleCounter(state) { // 計(jì)算剩余數(shù)量 return state.counter * 2;
} }
})

動(dòng)作 - actions

添加業(yè)務(wù)邏輯,類似于controller

 
export default new Vuex.Store({
    actions: {
        add({ commit }) {
            setTimeout(() => {
commit('add')
}, 1000);
} }
})

vuex原理解析

任務(wù)分析

實(shí)現(xiàn)一個(gè)插件:聲明Store類,掛載$store Store具體實(shí)現(xiàn):
創(chuàng)建響應(yīng)式的state,
保存mutations、actions和getters 實(shí)現(xiàn)commit根據(jù)用戶傳入type執(zhí)行對(duì)應(yīng)mutation
實(shí)現(xiàn)dispatch根據(jù)用戶傳入type執(zhí)行對(duì)應(yīng)action,
同時(shí)傳遞上下文 實(shí)現(xiàn)getters,按照getters定義對(duì)state做派生
初始化:Store聲明、install實(shí)現(xiàn)

let Vue;
class Store {
  constructor(options = {}) {
    this._vm = new Vue({
      data: {
        $$state:options.state
      }
}); }
  get state() {
    return this._vm._data.$$state
}
  set state(v) {
    console.error('please use replaceState to reset state');
} }
function install(_Vue) {
  Vue = _Vue;
  Vue.mixin({
    beforeCreate() {
      if (this.$options.store) {
        Vue.prototype.$store = this.$options.store;
} }
}); }
export default { Store, install };

實(shí)現(xiàn)commit:根據(jù)用戶傳入type獲取并執(zhí)行對(duì)應(yīng)mutation

class Store {
 constructor(options = {}) {
// 保存用戶配置的mutations選項(xiàng)
   this._mutations = options.mutations || {}
 }
commit(type, payload) {
// 獲取type對(duì)應(yīng)的mutation
const entry = this._mutations[type]
   if (!entry) {
     console.error(`unknown mutation type: ${type}`);
     return
}
// 指定上下文為Store實(shí)例
// 傳遞state給mutation entry(this.state, payload);
} }

實(shí)現(xiàn)actions:根據(jù)用戶傳入type獲取并執(zhí)行對(duì)應(yīng)action

class Store {
  constructor(options = {}) {
// 保存用戶編寫的actions選項(xiàng) this._actions = options.actions || {}
// 綁定commit上下文否則action中調(diào)用commit時(shí)可能出問題!! // 同時(shí)也把a(bǔ)ction綁了,因?yàn)閍ction可以互調(diào)
const store = this
const {commit, action} = store
    this.commit = function boundCommit(type, payload) {
      commit.call(store, type, payload)
    }
    this.action = function boundAction(type, payload) {
      return action.call(store, type, payload)
    }
}
dispatch(type, payload) {
// 獲取用戶編寫的type對(duì)應(yīng)的action const entry = this._actions[type]
    if (!entry) {
      console.error(`unknown action type: ${type}`); 
return
}
// 異步結(jié)果處理常常需要返回Promise
    return entry(this, payload);
  }
}

實(shí)現(xiàn)getter,state的計(jì)算屬性

let Vue;
class Store {
  constructor(options) {
    // 定義響應(yīng)式的state
    // this.$store.state.xx
    // 借雞生蛋
    let computed={}
    Object.keys(options.getters).forEach(function (key) { 
      computed[key]=function () {
        return options.getters[key](options.state)
      } 
    })
   console.log(computed)
 
    this._vm = new Vue({
      data: {
        $$state: options.state
      },
      computed:computed
    })
    
    this._mutations = options.mutations
    this._actions = options.actions

    // 綁定this指向
    this.commit = this.commit.bind(this)
    this.dispatch = this.dispatch.bind(this)
  }
  get getters() {
    return this._vm
  }
  // 只讀
  get state() {
    return this._vm._data.$$state
  }

  set state(val) {
    console.error('不能直接賦值呀,請(qǐng)換別的方式??!天王蓋地虎!!');
    
  }
  
  // 實(shí)現(xiàn)commit方法,可以修改state
  commit(type, payload) {
    // 拿出mutations中的處理函數(shù)執(zhí)行它
    const entry = this._mutations[type]
    if (!entry) {
      console.error('未知mutaion類型');
      return
    }

    entry(this.state, payload)
  }

  dispatch(type, payload) {
    const entry = this._actions[type]

    if (!entry) {
      console.error('未知action類型');
      return
    }

    // 上下文可以傳遞當(dāng)前store實(shí)例進(jìn)去即可
    entry(this, payload)
  }
}

function install(_Vue){
  Vue = _Vue

  // 混入store實(shí)例
  Vue.mixin({
    beforeCreate() {
      if (this.$options.store) {
        Vue.prototype.$store = this.$options.store
      }
    }
  })
}

// { Store, install }相當(dāng)于Vuex
// 它必須實(shí)現(xiàn)install方法
export default { Store, install }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容