getters访问数据为undefined问题
本篇文章可能对你的帮助不大, 只是个人开发中的一些记录。不同的业务和应用场景可能问题不同。
在通过 uni-app 开发商城时,用户快捷登录之后,服务器返回一个 token 数据,我将其同步到 vuex module下的 user 模块中。
然后从登录页返回到用户页,并发起 http 请求,获取用户的个人信息。
但是在请求时,我会在请求拦截器中获取 vuex 中的 token 数据。如果存在就携带到请求头中和服务器做 OAuth 验证。如果不存在就直接不携带 token。
用户登录成功之后,返回到用户页发起请求,但是获取用户信息接口是必须做 OAuth 验证的。问题在于在请求拦截器中 不能通过 vuex 的 getter 正确获取到 token值,而是返回 undefined。
request.js
import Http from "xxx/http";
import store from "sotre";
const request = new Http({
? baseURL: xxxxx,
? timeout: 50000,
? // 省略
});
request.interceptors.request.use((config) => {
? let token, g_t;
? if (
? ? (g_t = store.getters[`user/token`]) ||
? ? (g_t = Storage.get(USER_TOKEN_KEY))
? ) {
? ? token = g_t.token || null;
? }
? if (token) {
? ? config.header["Authorization"] = "Bearer " + token;
? }
? return config;
});
问题在于 g_t = store.getters[user/token] 获取的值为 undefined。
经过排查发现,vuex 中 getters 下的通过 state 获取的字段实现没有在 state 中定义。而是通过异步登录之后,才将其设置到 user 模块下的 state 中,使其变为不是响应式的。
写一个类似例子
<!DOCTYPE html>
<html lang="en">
<head>
? <meta charset="UTF-8">
? <title>Title</title>
</head>
<body>
<div id="app">
? <p>姓名: {{ realName }}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg测试数据/vuex@3.3.0/dist/vuex.js"></script>
<script type="module">
? Vue.use(Vuex);
? const store = new Vuex.Store({
? ? state: {},
? ? mutations: {
? ? ? change(state, data) {
? ? ? ? state.name = data;
? ? ? }
? ? },
? ? getters: {
? ? ? name: state => {
? ? ? ? return state.name;
? ? ? }
? ? }
? });
? new Vue({
? ? el: "#app",
? ? store,
? ? data: {
? ? ? message: "Hello"
? ? },
? ? computed: {
? ? ? realName() {
? ? ? ? return this.$store.getters.name;
? ? ? }
? ? },
? ? created() {
? ? ? setTimeout(() => {
? ? ? ? this.$store测试数据mit('change', 'zhangsan');
? ? ? })
? ? }
? })
</script>
</body>
</html>
异步代码执行的时候, state 中并没有 name 属性。所以一开始 getters 下的 realName 就算是 undefined。异步代码提交的 commit,在想 state 中新增 name 字段,但是它已不是响应式的。
解决方法:
就是提前在 state 中定义 getters 需要的某些字段,异步变更 state 中的字段它也是响应式的。getters 的值也会进行计算。
getters 类似于 vue 中的计算属性。
修改上面的代码为:
const store = new Vuex.Store({
? ? state: {
?? ??? ?name: ""
?? ?},
? ? // 省略...
? }) ?
这样 getters 的值会根据 name的值改变而进行计算。
项目中的代码比上面的例子更复杂,但是问题是类似的。经过排查后才发现,所以在博客中总结一下。
小结: 使用 vuex 时, getters 中需要计算的 state 属性一定要提前声明,使其成为响应式的值。
vuex getters(组件mounted调用)使用注意
逻辑
state存储数据(一开始为空数据,通过网络请求后更新数据) 在组件mounted中先调用actions方法通过mutations更新state数据, 接着组件mounted在调用getters 操作state中的数据,供组件使用mounted(){
// 进入组件立即发送网络请求获取商品信息
this.$store.dispatch('detail/getCommdityInfo',this.skuId)
console.log(this.skuInfo) //为undefined
console.log(this.cateNav) //控制台报错
}
state: {
commdityData:{}
},
mutations: {
SET_COMMDITY_LIST(state,value){
state测试数据mdityData = null
// 将商品信息存入组件内
state测试数据mdityData = value
console.log('state测试数据mdityData',state测试数据mdityData)
}
},
actions: {
async getCommdityInfo(context,query){
const res = await getCommdityDetail(query)
context测试数据mit('SET_COMMDITY_LIST',res.data.data)
}
},
getters:{
skuInfo:state => state测试数据mdityData.skuInfo,
cateNav:state => {
const {category1Name,category2Name,category3Name} = state测试数据mdityData.categoryView
return [category1Name,category2Name,category3Name]
},
}
结果报错: 组件在mouted 调用getters属性时,getters属性读取state数据(一开始为空),读取不到数据
* *原因:** 组件调用actions执行异步网络请求,通过mutations更新state数据还没有来得及执行
解决方案
更改getters中操作数据的属性,try-catch错误处理
cateNav:state => {
// 使用情景,组件在mounted中调用,getters 的属性时,此时state未更新;解构会出错,所以要错误处理!!
try{
const {category1Name,category2Name,category3Name} = state测试数据mdityData.categoryView
return [category1Name,category2Name,category3Name]
}
catch{
return {}
}
},
!!!注意:在组件的methods中写方法调用则可正常使用getters的数据!!
控制台输出:
1:mounted 输出
2:methods 方法的输出
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。
查看更多关于vuex通过getters访问数据为undefined问题及解决的详细内容...