vuex狀態初始化中間件設計

總算把最近嘗試的東西實現出來了,寫點文章沉澱一下。javascript

前言

單頁面應用在使用單向數據流的設計方案後,狀態樹的控制就變得相當重要。這裏面對的問題在於一個最基礎的點,同時也是最經常使用的一點 -- 初始狀態的控制與恢復
每次切換到一個頁面,若是是動態數據頁面,老是會先加載一些默認數據,或者清空現有數據,換句話說,就是初始化一下。
在以前使用vue + vuex的過程當中,對於狀態初始化的設計思路,是將其放到一個全局服務中,這樣每次進到不一樣頁面,只須要調用同一個全局的動做,就能完成初始化。同時,具體的初始化狀態值,則由每一個模塊本身控制。
vuex init design前端

問題

在查看了vuex源碼後,發現對於vuex的module而言,只是將全部module放到了同一個vm對象中,而後watch了一下。筆者以前在申明module中state對象時,常常使用const關鍵字,用意是認爲申明時的state值一直做爲靜態值存在着,表明可返回的初始狀態。而看了源碼後,被打臉打飛了。。。。
那麼怎麼纔能有一個靜態的初始狀態,讓咱們在切換頁面時可以恢復呢?固然,最好這個初始狀態時可以根據狀況,可更替的。換句話說,這個所謂初始狀態,應該是一個可定義的用於恢復的靜態狀態。vue

解決方案

Talk is cheap, show me the code.java

來來來,一言不合就上代碼~
源碼以及相關樣例能夠在個人github上找到,連接點此git

import Vue from 'vue'

function deepClone(obj) {
  if (Array.isArray(obj)) {
    return obj.map(deepClone)
  } else if (obj && typeof obj === 'object') {
    var cloned = {}
    var keys = Object.keys(obj)
    for (var i = 0, l = keys.length; i < l; i++) {
      var key = keys[i]
      cloned[key] = deepClone(obj[key])
    }
    return cloned
  } else {
    return obj
  }
}

const commonMutations = {
  INIT_STATE(state, moduleName) {
    state[moduleName] = deepClone(state.cache[moduleName])
  },
  CACHE_STATE(state, moduleName, newState) {
    state.cache[moduleName] = deepClone(newState)
  },
}

const commonActions = {
  initComponent({ dispatch }, name) {
    dispatch('INIT_STATE', name)
  },
  changeCacheState(store, module, state = store._vm[module]) {
    store.dispatch('CACHE_STATE', module, state)
  }
}

export default {
  onInit(state, store) {
    // hot load common mutations
    store.hotUpdate({
      mutations: commonMutations
    })
    // cache init state
    store._setupModuleState(state, {
        cache: {
          state: deepClone(state)
        }
      })
      // mixin all actions to the root vm
    Vue.mixin({
      vuex: {
        actions: commonActions
      }
    })
  }
}

關鍵點解讀

1. 深層克隆

這裏deep copy用了vuex源碼裏util的一個方法,官方註釋上寫着說比JSON.parse(JSON.stringify(obj))要來的更快,因而我就參(fu)考(zhi)過來了~~
什麼?爲何要深拷貝?由於咱們要維護一個靜態狀態的前端臨時倉庫呀~就像是前端的臨時數據庫同樣,所謂數據驅動嘛~
因而下一步就是咱們怎麼把這個臨時的靜態狀態對象讓全局可以共享。這裏用的方法就是一塊兒扔到store綁定的vm對象上去github

2. 全局使用便捷性

爲了可以讓代碼全局都享受到這個便捷性,筆者在這裏利用了vuex的中間件。vuex的中間件有2個特色,首先它提供了init與mutate動做的切入口。其次是它與store有着緊密聯繫。也所以,能夠知足咱們便捷性須要用到的2個需求:vuex

  1. 應用啓動時註冊數據庫

  2. 應用全局可調用,不須要另外引入spa

因此就將init須要用到的commonMutation經過hotupdate的方式,在module初始化的時候,將init模塊註冊到全局,同時在store中加上當前模塊初始狀態的深拷貝
此外,利用了vue自己的mixin機制,將commonActions註冊到全局的vm對象上
這樣作的結果是什麼呢?
去看看demo吧~~
地址在此設計

相關文章
相關標籤/搜索