1

问题

在开发中,有一些全局数据,比如用户数据,系统数据等。这些数据很多组件中都会使用,我们当然可以每次使用的时候都去请求,但是出于程序员的“洁癖”、“抠”等等优点,还是希望一次请求,到处使用。

这时候很自然的想到存储在 localStorage 中,但是有个问题是,这些数据可能会变,如果没能及时同步的话,就会用到不正确的数据,即使做了数据同步,但是 localStorage 中的数据不是响应式的,不能自动更新使用到这些数据的地方。这时候就想要开始使用 vuex 了。

但是在使用 vuex 的时候也遇到很多问题,比如,“一刷新就没啦”:

  • vuex 的数据是存储在浏览器维护的内存中,页面刷新会重新初始化,简单的说,就是没了。
  • localStorage 的数据是存储在浏览器维护的一个简单数据库里面,在本地文件中存储,所以可以“持久化”存在。

所以“一刷新就没啦”是很正常的,虽然现在很少需要用户去刷新页面,但是如果一刷新,数据没了,页面报错了,这也是无法接受的!

解决

比如:请求数据的接口都在 src/api 下面,其中用户相关的接口在 user.js中;
然后在 store 下有个 userInfo.js 的 module,用来存储用户数据以供全局使用(关于 vuex 模块化可以参看官方文档):

store
 |- modules
      |- userInfo.js
 |- index.js

userInfo.js中定义了 state, mutations, actions

import { getUserInfo } from '@/api/user';

const state = {
  user: null // 注意这里给的初始值是 null
}

const mutations = {
  setUserinfo (state, params) {
    state.user = params.user;
    localStorage.user = JSON.stringify(state.user); // 可以顺手存入 localStorage 中
  }
}

const actions = {
  async userinfo ({ commit }) {
    let ret = await getUserInfo();
    if (ret.data.retInt) { // 假如请求的数据成功返回
      commit('setUserinfo', {user: ret.data.retRes});
    }
  }
}

export default {
  state,
  mutations,
  actions
}

可以在组件内 mounted 的时候判断 state.userInfo.user 是否存在,如果不存在,马上请求数据并设置到store中:

mounted () {
  if (!this.$store.state.userInfo.user) {
    this.$store.dispatch('userinfo');
  }
}

当然,这个判断并请求的时机不一定要放在当前组件内,对于全局数据,可以在App.vue组件中去处理。

然后在组件内使用 store 中的数据,可以通过 computed 属性:

computed: {
  userInfo () {
    return this.$store.state.userInfo.user;
  }
}

使用 computed 属性的好处就是数据缓存和响应式,详细的可以参看官方文档关于 computed 属性的介绍。

注意

假如,现在组件中中只需要使用到用户的 age 属性,你可能会这么写:

computed: {
  userAge () {
    return this.$store.state.userInfo.user.age;
  }
}

然后,刷新页面,你就可能看到红红的一大片报错。

原因是,user 中的数据是异步请求来的,在组件渲染过程中使用 computed 的时候,user 中的数据还没有取回来,它的值是还是初始值,假如这个初始值是 nullundefined,那么读取 user.age 肯定会报错。最简单的办法就是初始值设置为 {} 一个空对象(mounted中的判断方式要调整)当然也可以在 computed 中进行判断处理。

现在,可以愉快的使用 vuex 了!

以上是自己在开发中填了坑之后的一点点心得,欢迎大家指点!


口袋里的战争
7 声望0 粉丝