乐趣区

关于vuex:两种方式解决页面刷新vuex中数据丢失问题详细讲解

问题形容

首先,对于 页面刷新 vuex 中数据失落问题 ,其实换种形式去形容就是: 页面刷新 vuex 中的数据又初始化问题

集体愚见:vuex 的数据并不是弄丢了,而是初始化了,回到初始值,回到原点了

对于 vuex 的用法本篇文章不赘述, 详情能够看之前的文章:https://segmentfault.com/a/11…

vuex 能够了解为是一个公共的空间,所有的组件都能够共享这个空间的状态数据,大家都能够(批改 or 读取)这个空间的数据,然而,这个空间的数据状态是有初始值的,举例页面上的菜单数据信息,因为菜单信息须要存储在 vuex 中,作为全局的共用共享的数据。

  • state 仓库中有一个 menuArr,初始值为一个空数组,这个空数组寄存的就是后端传递过去的动静菜单的数组数据,对于动静菜单能够看上一篇文章:https://segmentfault.com/a/11…
  • 拜访我的项目初始页面为登录页,用户登录胜利当前,会发申请获取后端返回的动静菜单的数据,而后把这个数据寄存在 vuex 中的 state 中的 menuArr 外面,同时进行页面跳转到我的项目首页
  • 这时,页面上的左侧菜单栏组件读取 vuex 中的 menuArr 数据并渲染进去,用户就能够失常操作了。然而!
  • 当用户一刷新的时候(比方在首页刷新),路由不会变,还是在首页。然而:无论是 .vue 组件中的 data 中的数据,还是 vuex 中的 state 中的数据,都会回归到初始状态
  • 所以 vuex 中的 menuArr 数组又会变成空数组,又因为 vue 是响应式的,当 menuArr 为空数组的时候,左侧菜单栏组件就渲染不进去货色,所以就没了,所以看着就像:页面刷新数据失落

剖析分明了问题产生的起因,接下来就是想方法去解决。

解决方案一 本地存储一份

login 页面

在 login.vue 组件中的登录中咱们去触发 action,申请的接口能够写在 action 外面,也能够写在组件外面。这里因为须要复用 action,所以申请我就写在 action 外面了。

/* login.vue 页面 */
<template>
  <div class="loginBox">
    <el-button type="primary" @click="loginIn"> 点击登录 </el-button>
  </div>
</template>

<script>
export default {
  name: "CodeLogin",
  methods: {loginIn() {this.$store.dispatch("naviBar/getMenu") // 告诉 action 去发申请
      this.$router.push({path: "/"}) // 跳转到首页
    },
  },
};
</script>

vuex 中的 naviBar 模块

/* vuex 中的 naviBar 模块 */

// 为了发申请,须要有一个 vue 实例
import Vue from 'vue'
const that = new Vue()

/* vuex 数据刷新失落,解决方案一,本地存一份 */
const naviBar = {
    state: {menuArr: JSON.parse(sessionStorage.getItem('menuArr')) ? JSON.parse(sessionStorage.getItem('menuArr')) : []},
    mutations: {setMenu(state, payload) {state.menuArr = payload},
    },
    actions: {async getMenu({ commit}, menu) {let res = await that.$api.getMenuData()
            console.log('菜单数据', res);
            sessionStorage.setItem('menuArr', JSON.stringify(res.data)) // 本地存储一份
            commit("setMenu", res.data) // 提交 mutation
        },
    },
    namespaced: true
}
export default naviBar

在须要应用 vuex 中的数据的中央,也就是 home.vue 首页的中央,间接应用计算属性取到相应 vuex 数据,在 html 中应用即可。computed: {menuArr(){return this.$store.state.naviBar.menuArr} }

计划剖析

此计划解决了问题,然而如果用户手动把浏览器的 Application 中的 sessionstorage 中存储 vuex 的数据清空,用户一刷新还是会失落,左侧的菜单还是会没了。

路人甲:用户会这样操作吗,黑人问号?

所以咱们就思考应用第二种形式,当页面刷新的时候,再从新发一次申请即可(不应用浏览器存储了)

解决方案一 页面刷新重发申请

login.vue 页面不必动

vuex 中的 naviBar 模块

页面刷新重发申请,vuex 就不须要写太简单了。

// 为了发申请,须要有一个 vue 实例
import Vue from 'vue'
const that = new Vue()

/* vuex 数据刷新失落,解决方案二,再从新发申请 */
const naviBar = {
    state: {menuArr: []
    },
    mutations: {setMenu(state, payload) {state.menuArr = payload},
    },
    actions: {async getMenu({ commit}, menu) {let res = await that.$api.getMenuData()
            commit("setMenu", res.data)
        },
    },
    namespaced: true
}
export default naviBar

外层页面重发申请

留神是外层视图,这个依据 vue 我的项目的视图构造去抉择地位。我在 home.vue 中书写,因为这个页面也须要应用到 vuex 中的 menuArr 数据,也是外层视图

export default {
  name: "Home",
  created() {
    /* 
      留神因为数组是援用数据类型,所以 [] 不等于 [],这里转换成字符串进行比拟
      若 vuex 中的 menuArr 不是初始值,就再次发申请从新获取菜单栏的数据
      加一个判断算是优化吧,不加的话,用户登录的时候会发一次,首页组件加载的时候也会发一次申请。即缩小申请的发送次数
     */
    if (JSON.stringify(this.$store.state.naviBar.menuArr) == "[]") {this.$store.dispatch("naviBar/getMenu");
    }
  },
  computed: {menuArr() {return this.$store.state.naviBar.menuArr;},
  },
  ...
}

计划剖析

这中计划实现了成果,也缩小了本地存储的应用,不过减少了申请和次数。和上一种计划比拟,各有优缺点,具体用那种看业务。

其余计划

还能够应用插件包去解决,比方 vuex-persistedstate 等 …

退出移动版