vuex 閑置狀態重置方案
前言
大型單頁應用(後面都是指spa),我們往往會通過使用狀態管理器 vuex 去解決組件間狀態共享與狀態傳遞等問題。這種應用少則幾十個單頁,多則上百個單頁。隨著路由的頻繁切換,每個路由對應的 vuex 中的狀態將越來越多。為了做到頁面的極致優化,我們需要將那些閑置的狀態重置,以減小占用的內存空間。
什麽狀態可以重置
vuex 強調采用集中式存儲管理應用的所有組件的狀態,但是我們真把所有的狀態都放到 store 中去處理,你會發現開發起來非常痛苦。這裏如果想很好的把控哪些數據需要放到 store 中去管理,首先要理解 vuex 是用來解決什麽問題的。vuex 官網指出是為了解決多個組件共享狀態
而隨著業務場景越來越復雜,很多與後臺交互的邏輯也都放到了組件中,這樣代碼就變得很淩亂,vuex 也沒有被充分利用。這時我們可以把與後臺 api 交互的邏輯放到 vuex 中的action 去處理,後臺返回的狀態自然也就放到了 store 管理。這樣處理後,組件就只負責對數據進行渲染,邏輯非常清晰。而此時,組件對應的 store 中的狀態隨著路由的切換將會越來越多,而這些狀態就需要我們手動的去清理了。
很多方案都有取舍,如果將與後臺 api 交互的數據放到組件中,就沒必要去清理了,但是代碼邏輯將變得比較亂。另外諸如 vuex 的插件 vue-devtools 將無法監控到每次請求數據的變化...
什麽時候去重置狀態
我們想要的效果是在路由切換的時候,把上一個路由對應的 vuex 中的狀態重置掉,但是路由和vuex 並沒有一一對應的關系,如果要做到這種效果,那麽我們需要維護一個路由與vuex 模塊的對應關系,這樣會很繁瑣。不如當路由改變時去重置 vuex 中的所有狀態。
vuex 中閑置狀態如何清理
下面將結合我的github實例去說明,這個實例創建了一個單頁應用,我們通過切換路由的時候將閑置的狀態清除。
改造路由對應組件的 module 狀態
實例中采用拆分 store 為多個 module 的方式,將路由對應的組件狀態放到對應的 module 中,多組件共享的狀態放到頂級的 store 中管理。大致如下:
// 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()
,代表路由改變的時候需要重置,當然這個方法名稱是個約定,你也可以定義為其他名稱。改造後為:
// store/modules/page1.js
// 放置你要重置的數據
const initState = {
page1Data: [],
}
// state
const state = {
// 參數解構
...initState,
// 路由改變不想重置的數據
page1Title: '',
initState(){
return initState
}
}
全局 module 配置
定義全局 mutation 事件類型
// store/types.js
export const RESET_STATES = 'resetStates'
定義全局 mutation
// 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 狀態的一種方案,如果有更好方案還請各位看官留言。如有不妥的地方也歡迎拍磚留言。
--完--
原文地址:https://segmentfault.com/a/1190000012686781
vuex 閑置狀態重置方案