大型單頁應用(後面都是指spa),咱們每每會經過使用狀態管理器 vuex 去解決組件間狀態共享與狀態傳遞等問題。這種應用少則幾十個單頁,多則上百個單頁。隨着路由的頻繁切換,每一個路由對應的 vuex 中的狀態將愈來愈多。爲了作到頁面的極致優化,咱們須要將那些閒置的狀態重置,以減少佔用的內存空間。vue
vuex 強調採用集中式存儲管理應用的全部組件的狀態,可是咱們真把全部的狀態都放到 store 中去處理,你會發現開發起來很是痛苦。這裏若是想很好的把控哪些數據須要放到 store 中去管理,首先要理解 vuex 是用來解決什麼問題的。vuex 官網指出是爲了解決多個組件共享狀態的,那麼咱們就能夠把多個組件的共享狀態放到 store 中去管理,這裏的多組件共享對於單頁應用不少狀況是跨路由的組件。若是 store只存儲多組件共享的狀態,那麼咱們就不必去清理 vuex 中的狀態了,由於這些狀態隨時會被用到。git
而隨着業務場景愈來愈複雜,不少與後臺交互的邏輯也都放到了組件中,這樣代碼就變得很凌亂,vuex 也沒有被充分利用。這時咱們能夠把與後臺 api 交互的邏輯放到 vuex 中的action 去處理,後臺返回的狀態天然也就放到了 store 管理。這樣處理後,組件就只負責對數據進行渲染,邏輯很是清晰。而此時,組件對應的 store 中的狀態隨着路由的切換將會愈來愈多,而這些狀態就須要咱們手動的去清理了。github
不少方案都有取捨,若是將與後臺 api 交互的數據放到組件中,就不必去清理了,可是代碼邏輯將變得比較亂。另外諸如 vuex 的插件 vue-devtools 將沒法監控到每次請求數據的變化...
咱們想要的效果是在路由切換的時候,把上一個路由對應的 vuex 中的狀態重置掉,可是路由和vuex 並無一一對應的關係,若是要作到這種效果,那麼咱們須要維護一個路由與vuex 模塊的對應關係,這樣會很繁瑣。不如當路由改變時去重置 vuex 中的全部狀態。web
下面將結合個人github實例去說明,這個實例建立了一個單頁應用,咱們經過切換路由的時候將閒置的狀態清除。vuex
實例中採用拆分 store 爲多個 module 的方式,將路由對應的組件狀態放到對應的 module 中,多組件共享的狀態放到頂級的 store 中管理。大體以下:chrome
// store/index.js import page1 from "./modules/page1.js"; import page2 from "./modules/page2.js"; import page3 from "./modules/page3.js"; import page4 from "./modules/page4.js"; import page5 from "./modules/page5.js"; export default new Vuex.Store({ state, getters, actions, mutations, modules: { // 每一個路由對應的 module page1, page2, page3, page4, page5 }, plugins: __DEV__ ? [createLogger()] : [], strict: __DEV__ ? true : false });
路由 page1 對應的 module 的 state 形如:後端
// store/modules/page1.js const state = { // 列表數據 page1Data: [], // 標題數據 page1Title: '' }
這些數據是經過調用後端 api 返回並複製的數據,若是咱們在路由改變的時候重置這些數據,那麼須要將初始化數據提取出來,而且暴露一個須要重置的標識方法 initState()
,表明路由改變的時候須要重置,固然這個方法名稱是個約定,你也能夠定義爲其餘名稱。改造後爲:api
// store/modules/page1.js // 放置你要重置的數據 const initState = { page1Data: [], } // state const state = { // 參數解構 ...initState, // 路由改變不想重置的數據 page1Title: '', initState(){ return initState } }
定義全局 mutation 事件類型瀏覽器
// store/types.js export const RESET_STATES = 'resetStates'
定義全局 mutationapp
// store/mutation.js import * as types from './types' // 檢測全部的 state 並把 `initState()` 中的屬性重置 function resetState(state, moduleState) { const mState = state[moduleState]; if (mState.initState && typeof mState.initState === 'function') { const initState = mState.initState(); for (const key in initState) { mState[key] = initState[key]; } } } export default { [types.RESET_STATES](state, payload) { for (const moduleState in state) { resetState(state, moduleState); } }, }
定義全局 action
// store/action.js import * as types from './types' export default { // rest state action resetStates:function (context, payLoad) { context.commit(types.RESET_STATES, payLoad); } }
至此一切準備就緒,只須要在路由改變時觸發重置的方法便可,在入口 vue 文件中處理
// components/app.vue <script> import {mapState, mapActions} from "vuex" export default{ methods: { ...mapActions({ resetStates: "resetStates" }) }, watch: { $route(to, from) { // 路由改變發起重置 this.resetStates(); } } } </script>
若是你的 chrome 瀏覽器安裝了 vuejs-devtools 在路由切換的時候就可以很清晰的看到上一個路由數據的的重置過程。
實例點這裏。咱們這裏的 vuex 狀態重置,是每次路由切換遍歷全部的 store 中的狀態,並把initState()
中的屬性重置,若是能作到把當前的路由對應的 state 重置就更好了,可是路由和 store 中的 module 並無關聯關係。這裏只是提供一種重置 vuex 狀態的一種方案,若是有更好方案還請各位看官留言。若有不妥的地方也歡迎拍磚留言。
--完--