用Vue做項目開發很久了,對於vuex能用、會用,但是因為狀態脫離頁面和刷新丟失兩個原因,一直都有種抵觸,特別是一些簡單的數據都是通過query或者本地存儲就解決了,然而對於一些復雜內容,不可避免的還是要使用Vuex去處理(真香),但是刷新丟失的問題,的確叫人頭大。最近閑下來,我們來研究下怎么干掉這個問題~
不大了解Vuex的同學,可以先去官網溜溜
由於Vuex的數據是存儲在內存中的,相當於memory cache,當頁面刷新的時候內存被清空重載新內容,原來的數據就丟了,為了解決這個我們可以借助瀏覽器的本地存儲來解決,此時我們有兩個選擇
- localStorage 真·持久存儲
- sessionStorage 會話期存儲
相比之下localStorage太持久了,不主動清除都會一直在,而sessionStorage更符合Vuex會話期狀態管理的設計初衷。因此下文中統一使用sessionStorage來做補充,解決問題。
有了補充對象之后,我們要做的只有兩點
1、每次在mutation中set state的時候,同步的塞到sessionStorage一份
2、狀態初始化的時候,從sessionStorage中讀取相應內容並作為默認值(存在的話)
看起來很簡單,於是第一版方案有了,
export default new Vuex.Store({
state: {
userLevel: sessionStorage.getItem('userLevel') || ''
},
mutations: {
SET_USERLEVEL(state, userLevel) {
sessionStorage.setItem('userLevel', userLevel)
state.userLevel = userLevel
}
},
modules: {
}
})
這個是解決問題了,但是每個mutation都要sessionStorage.setItem一下實在有點麻煩,而且初始化還要都getItem一遍,我很懶不想寫。。。於是我們改進了第二版
const storeMaker = (state) => {
// 初始化
Object.keys(state).map((key) => {
// 判斷類型獲取本地存儲數據
if (typeof state[key] === 'object') {
if (sessionStorage.getItem(key) && JSON.parse(sessionStorage.getItem(key))) {
state[key] = JSON.parse(sessionStorage.getItem(key))
}
} else if (typeof state[key] === 'number') {
if (sessionStorage.getItem(key) && parseInt(sessionStorage.getItem(key))) {
state[key] = parseInt(sessionStorage.getItem(key))
}
} else {
if (sessionStorage.getItem(key)) {
state[key] = sessionStorage.getItem(key)
}
}
})
// 重寫set處理
return new Proxy(state, {
set: function(target, key, value) {
let temp = value
if (typeof temp === 'object') {
temp = JSON.stringify(temp)
}
sessionStorage.setItem(key, temp)
return Reflect.set(target, key, value)
}
})
}
export default new Vuex.Store({
state: storeMaker({
userLevel: ''
}),
mutations: {
SET_USERLEVEL(state, userLevel) {
state.userLevel = userLevel
}
},
modules: {
}
})
內容不多,主要定義了一個storeMaker的函數實現了兩個功能
1、對傳入的state初始值判斷類型,並嘗試從sessionStorage中讀取數據替換默認值
2、通過Proxy重置state的set邏輯,添加同步保存到sessionStorage的邏輯
其實本來可以通過Proxy重置get邏輯處理取值的問題,但是由於vuex本身通過defineProperty函數重置了get邏輯,在這里使用proxy覆蓋會有沖突,因此在初始化的時候直接讀取sessionStorage。
同時也存在一些問題:
1、目前只處理了一級屬性,二級以下屬性沒處理,對於初始化會有偏差。對於這點處理層級也不宜過深,因為過深的結構設計本來就並不合理,兩層基本也足夠了。基本處理就是對於state的每個key再去遍歷一遍,如果是object(非null非數組非空對象)就重新proxy一下
2、可以嘗試打包成npm包,或者寫成Vuex的插件形式,方便使用
3、等等
~狀態不好,先寫到這,大家有興趣一起來討論,清清腦子再來補充~
聯想到的一些點:
1、memory cache和disk cache?內存怎么清理?js垃圾回收機制?
2、SessionStorage怎么做到會話期緩存?
3、session機制怎么回事?
4、http的無狀態?狀態保持?客戶端保持?服務端保持?
5、等等等等
發散開看看,一個地方真的能學到很多東西。。。