用 vue 做项目开发很久了, 对于 vuex 能用, 会用, 但是因为状态脱离页面和刷新丢失两个原因, 一直都有种抵触, 特别是一些简单的数据都是通过 query 或者本地存储就解决了, 然而对于一些复杂内容, 不可避免的还是要使用 Vuex 去处理 (真香), 但是刷新丢失的问题, 的确叫人头大. 最近闲下来, 我们来研究下怎么干掉这个问题~
不大了解 Vuex 的同学, 可以先去官网溜溜 https://vuex.vuejs.org/zh/
由于 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, 等等等等
发散开看看, 一个地方真的能学到很多东西...
来源: https://www.cnblogs.com/heioray/p/10284268.html