2、vuex页面刷新数据不保留,解决方法

这是一个vuex页面刷新引起的一系列问题

一 、场景:

VueX里存储了 this.$store.state.PV这样一个变量,这个变量是在app.vue里通过接口获取然后存储在vueX里的,在路由activity.vue中,我们需要用到这个变量,并且通过这个变量的值来控制路由页面里某一段dom元素的显示与否。

这个需求这样描述起来,是很好实现的。于是我就简单写了几段代码,很简单轻松的实现了这个需求:

我只需要在created生命周期里面,给posVersion这个变量赋值成this.$store.state.PV即可。

至此,这个需求看上去很“完美”的完成,没有任何问题。

。。。(很明显问题很大)

二、BUG场景:

测试的同学告诉说,首次进入路由,posVersion这个值为true的时候,dom元素正常显示,当用户F5刷新整个页面的时候,本应该继续显示的dom元素却不见了。

我复现了这个BUG,在created里面console.log(this.$store.state.PV),却输出了一个空。但是如果单纯刷新路由的话,dom元素还是可以正常显示的。

这是什么鬼呢到底?

在解决这个问题之前,我们先了解几个概念:

三、什么是VueX?

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。在我看来 vuex 就是把需要共享的变量全部存储在一个对象里面,然后将这个对象放在顶层组件中供其他组件使用,它是另一种意义上的变量提升。

四、路由刷新

路由刷新是无刷新跳转,表面看起来就像是一个app应用,表现效果就像你写的 tab 选项卡,所有的数据都还存在内存里(store里),页面是无重载的。

五、F5页面刷新

F5刷新做了什么事呢,重新载入页面,销毁之前所有的数据。

所以,这个bug出现的问题就很好理解了,F5页面刷新,页面销毁之前的资源,重新请求,因此写在生命周期里的vuex数据是重新初始化,无法获取的,这也就是为什么会打印出空的原因。

那么既然知道问题的原因了?应该怎么处理这个问题。

数据刷新vuex重置,在created中获取this.$store.state.PV数据时,还是空的,后面的生命周期才进行的赋值(推荐用computed)

解决思路1:

Localstorage 这是很容易想到的方法。将this.$store.state.PV存入到缓存里之后,然后监听页面重载事件,如果页面重新载入了,那就从缓存里读取数据,然后赋值,这样我们的dom元素就又可爱的回到了文档中间。

这个方法可以解决这个问题。但是如果需要用到localstorage的话,我完全可以让我的蒙蒙小伙伴在取到pv的值的时候直接存到缓存里,然后我直接用就可以,完全就不能出现这个问题,而且就算我自己存的话,也是相对繁琐的过程。(本方法未考虑接口返回慢的情况,请杠精少年不要太杠,不然下班跟我去搬砖)

PASS!

解决方法2:

vue官方文档,有这样一段话:

计算属性的结果会被缓存,除非依赖的响应式 property 变化才会重新计算。注意,如果某个依赖 (比如非响应式 property) 在该实例范畴之外,则计算属性是不会被更新的。

在此之前我曾经想过watch方法来监听this.pvVersion这个变量,但是在页面重载的时候watch方法也是重新进行计算加载的,所以我们可以选择计算属性这个方法来尝试解决这个问题,并且官方文档给出的解释当中也提到了缓存,也就是如果有缓存的情况下computed会优先使用缓存,于是我在activity.vue里写下来computed

我怀着忐忑的心情,去手动刷新了页面,结果,本应该显示出来的dom元素,果然很给面子的显示了出来。

Computed属性的优点我试着来总结一下:
1. 纯响应式,computed里面所用到的data一旦改变,整个computed的方法就回重新计算这个属性值

2. 计算结果会被缓存起来,方便下次使用,如果下次调用的时候,其中的数据没有发生变化,则不会重新计算。

所以我们要善用computed属性去解决实际开发

注: 实际使用时当vuex值变化时,F5刷新页面,vuex数据重置为初始状态,所以还是要用到localStorage或sessionStorage或cookie


我实际用到的

获取数据时尽量在computed中进行获取

一、补充本地存储 localStorage

在App.vue中使用

created(){
    //在页面加载时读取localStorage里的状态信息
    localStorage.getItem("userMsg") && this.$store.replaceState(Object.assign(this.$store.state,JSON.parse(localStorage.getItem("userMsg"))));
    
    //在页面刷新时将vuex里的信息保存到localStorage里
    window.addEventListener("beforeunload",()=>{
        localStorage.setItem("userMsg",JSON.stringify(this.$store.state))
    })
  }

二、插件vuex-persistedstate

npm install vuex-persistedstate  --save
引入及配置

在store下的index.js中

import createPersistedState from "vuex-persistedstate"
const store = new Vuex.Store({
  // ...
  plugins: [createPersistedState()]
})

store
store

存储到sessionStorage(cookie与localStore一样):

import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'
import user from './modules/user'
import createPersistedState from "vuex-persistedstate" // vuex-persistedstate默认持久化所有state,指定需要持久化的state
Vue.use(Vuex)

export default new Vuex.Store({
  modules: { user },
  getters,
  plugins: [
    createPersistedState({
      storage: window.sessionStorage
    })
  ]
})

vuex-persistedstate默认持久化所有state,指定需要持久化的state,配置如下:
plugins后面加数组可以配置多个

import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'
import user from './modules/user'
import createPersistedState from "vuex-persistedstate" // vuex-persistedstate默认持久化所有state,指定需要持久化的state
Vue.use(Vuex)

export default new Vuex.Store({
  modules: { user },
  getters,
  plugins: [
    createPersistedState({
      storage: window.sessionStorage,
      reducer(val) {
          return {
          // 只储存state中的user
          user: val.user
        }
    }
    })
  ]
})

总结

使用vuex是为了跨页面的数据响应
在初始时可以先从本地缓存中获取,这些数据在mutations赋值时也要存到本地缓存中,当然清理时也不要忘了。
(现在比较常用这种方法)

exp:

1、store/module/user.js

export default {
  state: {
    // 登录时返回的信息
    userInfo: window.localStorage.getItem('USERINFO') || {},
  },
  getters: {
    // 登录时返回的信息
    userInfo(state) {
      return state.userInfo
    },
  },
  mutations: {
    SET_LOGININFO: (state, userInfo) => {
      state.userInfo= userInfo
      window.localStorage.setItem('USERINFO', userInfo)
    }
  },
  actions: {
    LoginActions ({ commit, state}, userInfo) {
       return new Promise((resolve, reject) => {
          loginFn(userInfo).then(res=>{
            commit('SET_LOGININFO', res.data)
          })
       })
    }
  }
}

2、使用

import { mapGetters, mapActions } from 'vuex'
export default {
  data(){
    return{
      loginInfo:{}
    }
  },
  computed: {
    ...mapGetters(['userInfo'])
  },
  mounted(){
    this.LoginActions(loginInfo)
  },
  methods:{
    ...mapActions(['LoginActions'])
  }
}
posted @ 2018-08-31 19:14  飞刀还问情  阅读(38306)  评论(3编辑  收藏  举报