vuex通過(guò)getters訪問(wèn)數(shù)據(jù)為undefined問(wèn)題及解決
getters訪問(wèn)數(shù)據(jù)為undefined問(wèn)題
本篇文章可能對(duì)你的幫助不大, 只是個(gè)人開(kāi)發(fā)中的一些記錄。不同的業(yè)務(wù)和應(yīng)用場(chǎng)景可能問(wèn)題不同。
在通過(guò) uni-app 開(kāi)發(fā)商城時(shí),用戶快捷登錄之后,服務(wù)器返回一個(gè) token 數(shù)據(jù),我將其同步到 vuex module下的 user 模塊中。
然后從登錄頁(yè)返回到用戶頁(yè),并發(fā)起 http 請(qǐng)求,獲取用戶的個(gè)人信息。
但是在請(qǐng)求時(shí),我會(huì)在請(qǐng)求攔截器中獲取 vuex 中的 token 數(shù)據(jù)。如果存在就攜帶到請(qǐng)求頭中和服務(wù)器做 OAuth 驗(yàn)證。如果不存在就直接不攜帶 token。
用戶登錄成功之后,返回到用戶頁(yè)發(fā)起請(qǐng)求,但是獲取用戶信息接口是必須做 OAuth 驗(yàn)證的。問(wèn)題在于在請(qǐng)求攔截器中 不能通過(guò) 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; });
問(wèn)題在于 g_t = store.getters[user/token] 獲取的值為 undefined。
經(jīng)過(guò)排查發(fā)現(xiàn),vuex 中 getters 下的通過(guò) state 獲取的字段實(shí)現(xiàn)沒(méi)有在 state 中定義。而是通過(guò)異步登錄之后,才將其設(shè)置到 user 模塊下的 state 中,使其變?yōu)椴皇琼憫?yīng)式的。
寫(xiě)一個(gè)類(lèi)似例子
<!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.com/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.commit('change', 'zhangsan'); ? ? ? }) ? ? } ? }) </script> </body> </html>
異步代碼執(zhí)行的時(shí)候, state 中并沒(méi)有 name 屬性。所以一開(kāi)始 getters 下的 realName 就算是 undefined。異步代碼提交的 commit,在想 state 中新增 name 字段,但是它已不是響應(yīng)式的。
解決方法:
就是提前在 state 中定義 getters 需要的某些字段,異步變更 state 中的字段它也是響應(yīng)式的。getters 的值也會(huì)進(jìn)行計(jì)算。
getters 類(lèi)似于 vue 中的計(jì)算屬性。
修改上面的代碼為:
const store = new Vuex.Store({ ? ? state: { ?? ??? ?name: "" ?? ?}, ? ? // 省略... ? }) ?
這樣 getters 的值會(huì)根據(jù) name的值改變而進(jìn)行計(jì)算。
項(xiàng)目中的代碼比上面的例子更復(fù)雜,但是問(wèn)題是類(lèi)似的。經(jīng)過(guò)排查后才發(fā)現(xiàn),所以在博客中總結(jié)一下。
小結(jié):使用 vuex 時(shí), getters 中需要計(jì)算的 state 屬性一定要提前聲明,使其成為響應(yīng)式的值。
vuex getters(組件mounted調(diào)用)使用注意
邏輯
- state存儲(chǔ)數(shù)據(jù)(一開(kāi)始為空數(shù)據(jù),通過(guò)網(wǎng)絡(luò)請(qǐng)求后更新數(shù)據(jù))
- 在組件mounted中先調(diào)用actions方法通過(guò)mutations更新state數(shù)據(jù),
- 接著組件mounted在調(diào)用getters 操作state中的數(shù)據(jù),供組件使用
mounted(){ // 進(jìn)入組件立即發(fā)送網(wǎng)絡(luò)請(qǐng)求獲取商品信息 this.$store.dispatch('detail/getCommdityInfo',this.skuId) console.log(this.skuInfo) //為undefined console.log(this.cateNav) //控制臺(tái)報(bào)錯(cuò) }
state: { commdityData:{} }, mutations: { SET_COMMDITY_LIST(state,value){ state.commdityData = null // 將商品信息存入組件內(nèi) state.commdityData = value console.log('state.commdityData',state.commdityData) } }, actions: { async getCommdityInfo(context,query){ const res = await getCommdityDetail(query) context.commit('SET_COMMDITY_LIST',res.data.data) } }, getters:{ skuInfo:state => state.commdityData.skuInfo, cateNav:state => { const {category1Name,category2Name,category3Name} = state.commdityData.categoryView return [category1Name,category2Name,category3Name] }, }
結(jié)果報(bào)錯(cuò):組件在mouted 調(diào)用getters屬性時(shí),getters屬性讀取state數(shù)據(jù)(一開(kāi)始為空),讀取不到數(shù)據(jù)
**原因:**組件調(diào)用actions執(zhí)行異步網(wǎng)絡(luò)請(qǐng)求,通過(guò)mutations更新state數(shù)據(jù)還沒(méi)有來(lái)得及執(zhí)行
解決方案
更改getters中操作數(shù)據(jù)的屬性,try-catch錯(cuò)誤處理
cateNav:state => { // 使用情景,組件在mounted中調(diào)用,getters 的屬性時(shí),此時(shí)state未更新;解構(gòu)會(huì)出錯(cuò),所以要錯(cuò)誤處理?。? try{ const {category1Name,category2Name,category3Name} = state.commdityData.categoryView return [category1Name,category2Name,category3Name] } catch{ return {} } },
?。?!注意:在組件的methods中寫(xiě)方法調(diào)用則可正常使用getters的數(shù)據(jù)?。?/strong>
控制臺(tái)輸出:
1:mounted 輸出
2:methods 方法的輸出
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
vue.js+elementUI實(shí)現(xiàn)點(diǎn)擊左右箭頭切換頭像功能(類(lèi)似輪播圖效果)
這篇文章主要介紹了vue.js+elementUI實(shí)現(xiàn)點(diǎn)擊左右箭頭切換頭像功能(類(lèi)似輪播圖),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-09-09vuejs 制作背景淡入淡出切換動(dòng)畫(huà)的實(shí)例
今天小編就為大家分享一篇vuejs 制作背景淡入淡出切換動(dòng)畫(huà)的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-09-09使用Bootstrap + Vue.js實(shí)現(xiàn)添加刪除數(shù)據(jù)示例
本篇文章主要介紹了使用Bootstrap + Vue.js實(shí)現(xiàn) 添加刪除數(shù)據(jù)示例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-02-02vue?draggable組件實(shí)現(xiàn)拖拽及點(diǎn)擊無(wú)效問(wèn)題的解決
這篇文章主要介紹了vue?draggable組件實(shí)現(xiàn)拖拽及點(diǎn)擊無(wú)效問(wèn)題的解決,只需要在設(shè)置handle屬性就可以了,.defaultTypeTag 是要拖拽的塊的類(lèi)名,要注意的是需要做點(diǎn)擊事件的項(xiàng)不能包含在這個(gè)類(lèi)名里面,不然會(huì)無(wú)法觸發(fā)點(diǎn)擊事件,詳細(xì)解決辦法跟隨小編一起學(xué)習(xí)吧2022-05-05vue中el-form-item展開(kāi)項(xiàng)居中的實(shí)現(xiàn)方式
這篇文章主要介紹了vue中el-form-item展開(kāi)項(xiàng)居中的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-10-10Vue實(shí)現(xiàn)Excel本地下載及上傳的方法詳解
相信大家在項(xiàng)目中經(jīng)常會(huì)遇到一些上傳下載文件的相關(guān)功能。這篇文章將為大家介紹一下Vue實(shí)現(xiàn)Excel本地下載及上傳的示例代碼,需要的可以參考一下2022-07-07Vue Element前端應(yīng)用開(kāi)發(fā)之獲取后端數(shù)據(jù)
這篇文章主要介紹了Vue Element前端應(yīng)用開(kāi)發(fā)之獲取后端數(shù)據(jù),對(duì)vue感興趣的同學(xué),可以參考下2021-05-05