跟著文檔學(xué)Vuex(終章):模塊化(module)

一、為什么需要模塊化

前面我們講到的例子都在一個(gè)狀態(tài)樹里進(jìn)行,當(dāng)一個(gè)項(xiàng)目比較大時(shí),所有的狀態(tài)都集中在一起會得到一個(gè)比較大的對象,進(jìn)而顯得臃腫,難以維護(hù)。為了解決這個(gè)問題,Vuex允許我們將store分割成模塊(module),每個(gè)module有自己的state,mutation,action,getter,甚至還可以往下嵌套模塊,下面我們看一個(gè)典型的模塊化例子

const moduleA = {
  state: {....},
  mutations: {....},
  actions: {....},
  getters: {....}
}

const moduleB = {
  state: {....},
  mutations: {....},
  actions: {....},
  getters: {....}
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // moduleA的狀態(tài)
store.state.b // moduleB的狀態(tài)

二、模塊的局部狀態(tài)

模塊內(nèi)部的mutation和getter,接收的第一參數(shù)(state)是模塊的局部狀態(tài)對象,rootState

const moduleA = {
  state: { count: 0},
  mutations: {
    increment (state) {
      // state是模塊的局部狀態(tài),也就是上面的state
      state.count++
    }
  },
  getters: {
    doubleCount (state, getters, rootState) {
      // 參數(shù) state為當(dāng)前局部狀態(tài),rootState為根節(jié)點(diǎn)狀態(tài)
      return state.count * 2
    }
  },
  actions: {
    incremtnIfOddRootSum ( { state, commit, rootState } ) {
      // 參數(shù) state為當(dāng)前局部狀態(tài),rootState為根節(jié)點(diǎn)狀態(tài)
      if ((state.cont + rootState.count) % 2 === 1) {
        commit('increment')
      }
    }
  }
}

三、命名空間(這里一定要看,不然有些時(shí)候會被坑)

上面所有的例子中,模塊內(nèi)部的action、mutation、getter是注冊在全局命名空間的,如果你在moduleA和moduleB里分別聲明了命名相同的action或者mutation或者getter(叫some),當(dāng)你使用store.commit('some'),A和B模塊會同時(shí)響應(yīng)。所以,如果你希望你的模塊更加自包含和提高可重用性,你可以添加namespaced: true的方式,使其成為命名空間模塊。當(dāng)模塊被注冊后,它的所有g(shù)etter,action,mutation都會自動根據(jù)模塊注冊的路徑調(diào)用整個(gè)命名,例如:

const store = new Vuex.Store({
  modules: {
    account: {
      namespaced: true,
      state: {...}, // 模塊內(nèi)的狀態(tài)已經(jīng)是嵌套的,namespaced不會有影響
      getters: {      // 每一條注釋為調(diào)用方法
        isAdmin () { ... } // getters['account/isAdmin']
      },
      actions: {
        login () {...} // dispatch('account/login')
     },
      mutations: {
        login () {...} // commit('account/login')
      },
      modules: {     // 繼承父模塊的命名空間
        myPage : {
          state: {...},
          getters: {
            profile () {...}     // getters['account/profile']
          }
        },
        posts: {    // 進(jìn)一步嵌套命名空間
          namespaced: true,
          getters: {
            popular () {...}    // getters['account/posts/popular']
          }
        }
      }
    }
  }
})

啟用了命名空間的getter和action會收到局部化的getter,dispatch和commit。你在使用模塊內(nèi)容時(shí)不需要再同一模塊內(nèi)添加空間名前綴,更改namespaced屬性后不需要修改模塊內(nèi)的代碼。

四、在命名空間模塊內(nèi)訪問全局內(nèi)容(Global Assets)

如果你希望使用全局state和getter,roorState和rootGetter會作為第三和第四參數(shù)傳入getter,也會通過context對象的屬性傳入action
若需要在全局命名空間內(nèi)分發(fā)action或者提交mutation,將{ root: true }作為第三參數(shù)傳給dispatch或commit即可。

modules: {
  foo: {
    namespaced: true,
    getters: {
      // 在這個(gè)被命名的模塊里,getters被局部化了
      // 你可以使用getter的第四個(gè)參數(shù)來調(diào)用 'rootGetters'
      someGetter (state, getters, rootSate, rootGetters) {
        getters.someOtherGetter    // -> 局部的getter, ‘foo/someOtherGetter’
        rootGetters.someOtherGetter // -> 全局getter, 'someOtherGetter'
      }
    },
    actions: {
      // 在這個(gè)模塊里,dispatch和commit也被局部化了
      // 他們可以接受root屬性以訪問跟dispatch和commit
      smoeActino ({dispatch, commit, getters, rootGetters }) {
        getters.someGetter    // 'foo/someGetter'
        rootGetters.someGetter    // 'someGetter'
        dispatch('someOtherAction')      // 'foo/someOtherAction'
        dispatch('someOtherAction', null, {root: true})    // => ‘someOtherAction’
        commit('someMutation')    // 'foo/someMutation'
        commit('someMutation', null, { root: true })    // someMutation
      }
    }
  }
}

五、帶命名空間的綁定函數(shù)

前面說過,帶了命名空間后,調(diào)用時(shí)必須要寫上命名空間,但是這樣就比較繁瑣,尤其涉及到多層嵌套時(shí)(當(dāng)然開發(fā)中別嵌套太多,會暈。。)
下面我們看下一般寫法

computed: {
  ...mapState({
    a: state => state.some.nested.module.a,
    b: state => state.some.nested.module.b
  }),
  methods: {
    ...mapActions([
      'some/nested/module/foo',
       'some/nested/module/bar'
    ])
  }
}

對于這種情況,你可以將模塊的命名空間作為第一個(gè)參數(shù)傳遞給上述函數(shù),這樣所有的綁定會自動將該模塊作為上下文。簡化寫就是

computed: {
  ...mapStates('some/nested/module', {
    a: state => state.a,
    b: state => state.b
  })
},
methods: {
  ...mapActions('some/nested/module',[
    'foo',
    'bar'
  ])
}

六、模塊重用

有時(shí)我們可能創(chuàng)建一個(gè)模塊的多個(gè)實(shí)例,例如:

  • 創(chuàng)建多個(gè)store,他們共用一個(gè)模塊
  • 在一個(gè)store中多次注冊同一個(gè)模塊

如果我們使用一個(gè)純對象來聲明模塊的狀態(tài),那么這個(gè)狀態(tài)對象會通過引用被共享,導(dǎo)致數(shù)據(jù)互相污染。
實(shí)際上Vue組件內(nèi)data是同樣的問題,因此解決辦法也是一樣的,使用一個(gè)函數(shù)來聲明模塊狀態(tài)(2.3.0+支持)

const MyModule = {
  state () {
    return {
      foo: 'far'
    }
  }
}

七、總結(jié)

到這里模塊化(module)的內(nèi)容就已經(jīng)講完了,本次主要講解了module出現(xiàn)的原因,使用方法,全局和局部namespaced模塊命名空間,局部訪問全局內(nèi)容,map函數(shù)帶有命名空間的綁定函數(shù)和模塊的重用。

引用

https://vuex.vuejs.org Vuex官方文檔

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Vuex 是一個(gè)專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式。它采用集中式存儲管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)...
    白水螺絲閱讀 4,684評論 7 61
  • 安裝 npm npm install vuex --save 在一個(gè)模塊化的打包系統(tǒng)中,您必須顯式地通過Vue.u...
    蕭玄辭閱讀 2,963評論 0 7
  • vuex 場景重現(xiàn):一個(gè)用戶在注冊頁面注冊了手機(jī)號碼,跳轉(zhuǎn)到登錄頁面也想拿到這個(gè)手機(jī)號碼,你可以通過vue的組件化...
    sunny519111閱讀 8,035評論 4 111
  • 上一章總結(jié)了 Vuex 的框架原理,這一章我們將從 Vuex 的入口文件開始,分步驟閱讀和解析源碼。由于 Vuex...
    你的肖同學(xué)閱讀 1,806評論 3 16
  • Vuex 是什么? ** 官方解釋:Vuex 是一個(gè)專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式**。它采用集中...
    Rz______閱讀 2,318評論 1 10