詳解Vuex常見問題、深入理解Vuex

Vuex 是一個專為 Vue.js 應用程序開發的狀態管理模式。它采用集中式存儲管理應用的所有組件的狀態,并以相應的規則保證狀態以一種可預測的方式發生變化。

  狀態?我把它理解為在data中的屬性需要共享給其他vue組件使用的部分,就叫做狀態。簡單的說就是data中需要共用的屬性。

  使用Vue開發項目時,通常我們就會遇到如下幾種棘手的問題:

  問題1:通過路由傳遞參數,我們會采用params或者query形式,但這兩種方式都會在URL上做手腳,如果傳遞的參數過多,會導致400 Bad Request(如:點擊表格某行,攜帶行數據跳轉到新頁面進行查看)。?

  問題2:兄弟組件傳值?

  問題3:多處地方使用同一數據,為節省重復請求(最為常見)

  業務場景:

  從A頁面攜帶下鉆參數(ID)到B頁面,然后B頁面獲取參數(ID)進行數據請求。由于要下鉆的ID過長,受瀏覽器的URL長度限制問題,我們不能采用常規的prams(xxx.com/B/:ID)或query(xxx.com/B?ID=…)形式傳遞。可以使用Vuex做中間過渡,跳轉前存儲ID信息,進入B頁面后從Vuex獲取ID信息。

  如果用戶在B頁面刷新數據,則Vuex的ID狀態值會被清空無法獲取,這里只能借助localStorage進行持久化進行處理(當然,如果直接使用localstorage進行持久化存儲,而不借助Vuex也是可行的,但就是沒了響應式的效果了)

一、常見使用問題

1、Vuex,每次調用mutation之后向localstorage存值,防止刷新丟失

export default {state:{reportInfo:null},getters:{reportInfo(state){if(!state.reportInfo){state.reportInfo = JSON.parse(sessionStorage.getItem('reportInfo'))}return state.reportInfo}},mutations:{initReport:(state,data) => {state.reportInfo = datasessionStorage.setItem('reportInfo',JSON.stringify(data))},changeReportReview:(state,data) => {state.reportInfo.is_review = data;//改state的reportInfo里的某個值,
同時修改sessionStorage的值,以保證一樣sessionStorage.setItem('reportInfo',JSON.stringify(state.reportInfo))}}
}

?

2、調用時需要追加模塊名稱

  如上的getters,首先從store中獲取,如果store中不存在則從localstorage中獲取(刷新)

3、頁面中如果有用戶登出操作,此時一般需要removeItem,如果頁面中有userInfo的判斷信息,如下一般需要先做個判斷userInfo存在才會去取userInfo.roleName的值,這樣就會防止頁面報錯,類似于后臺語言空指針的錯誤

<span class="el-dropdown-link">{{userInfo ? (userInfo.account ? userInfo.account : userInfo.phoneNum) : ""}}<i class="iconfont icon-user"></i>
</span>
<router-link :to="'/account'" v-if="userInfo && userInfo.roleName === 'sys'"><el-dropdown-item>添加賬戶</el-dropdown-item>
</router-link>

  如果沒有removeItem的操作的話,則是不需要這樣的。如下面的reportInfo,因為用戶登出的時候,不會影響到它

<div class="suggess_requert" v-if="suggess.suggestion_level === 3"><div v-if="reportInfo.is_review === 1"><router-link v-if="userInfo && userInfo.roleName === 'dba'" :to="'/list/review'"><h3>提交審核意見</h3></router-link><h3 v-else>專家正在審核,請稍后</h3></div><router-link v-else-if="reportInfo.is_review === 2" :to="'/list/reviewInfo/' + reportInfo.report_id"><h3>查看云和恩墨專家團隊審核意見</h3></router-link><div v-else><h3 v-if="userInfo && userInfo.roleName === 'user'" @click="reviewRequest()">一鍵請求云和恩墨專家團隊幫您二次審核</h3></div>
</div>

?

?

4、state訪問狀態對象

  const state ,這個就是我們說的訪問狀態對象,它就是我們SPA(單頁應用程序)中的共享值。

  學習狀態對象賦值給內部對象,也就是把stroe.js中的值,賦值給我們模板里data中的值。有三種賦值方式:

(1)通過computed的計算屬性直接賦值

  computed屬性可以在輸出前,對data中的值進行改變,我們就利用這種特性把store.js中的state值賦值給我們模板中的data值。

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

  這里需要注意的是return this.$store.state.count這一句,一定要寫this,要不你會找不到$store的。這種寫法很好理解,但是寫起來是比較麻煩的,那我們來看看第二種寫法。

(2)通過mapState的對象來賦值

  我們首先要用import引入mapState。

import {mapState} from 'vuex';//然后還在computed計算屬性里寫如下代碼:
computed:mapState({count:state=>state.count  //理解為傳入state對象,修改為state.count屬性
})

  這里我們使用ES6的箭頭函數來給count賦值。

(3)通過mapState的數組來賦值

computed:mapState(["count"])

  這個算是最簡單的寫法了,在實際項目開發當中也經常這樣使用

5、模板獲取Mutations方法

  實際開發中我們也不喜歡看到$store.commit( )這樣的方法出現,我們希望跟調用模板里的方法一樣調用。 例如:@click=”reduce” 就和沒引用vuex插件一樣。要達到這種寫法,只需要簡單的兩部就可以了:

//1、用import 引入我們的mapMutations:
import {mapGetters,mapMutations} from 'vuex'
//2、添加methods屬性,并加入mapMutations
...mapMutations(['changeReportReview']),

  mapGetters、mapActions,都是一樣的用法

methods:{...mapMutations([  'add','reduce']),...mapActions(['addAction','reduceAction'])
},

  需要注意的是,(1)調用的時候都是需要加上this才能訪問到的;(2)getters/mutations/actions這些如果沒帶命名空間的話,就算是寫在module模塊里的這些方法,但是在使用的時候,是不需要加上模塊名稱的,而state是要加上模塊名稱的

二、狀態管理模式

  “單向數據流”理念的極簡示意:

  • state,驅動應用的數據源;
  • view,以聲明方式將?state?映射到視圖;
  • actions,響應在?view?上的用戶輸入導致的狀態變化。

  我們在開發中會遇到多個組件共享狀態時,單向數據流的簡潔性很容易被破壞。

  • 多個視圖依賴于同一狀態。
  • 來自不同視圖的行為需要變更同一狀態。

  對于問題一,傳參的方法對于多層嵌套的組件將會非常繁瑣,并且對于兄弟組件(非父子組件)間的狀態傳遞無能為力;

  對于問題二,我們經常會采用父子組件直接引用或者通過事件來變更和同步狀態的多份拷貝。以上的這些模式非常脆弱,通常會導致無法維護的代碼。

三、Vuex簡介

  Vuex 和單純的全局對象有以下兩點不同:

  • Vuex 的狀態存儲是響應式的。當 Vue 組件從 store 中讀取狀態的時候,若 store 中的狀態發生變化,那么相應的組件也會相應地得到高效更新。
  • 不能直接改變 store 中的狀態改變 store 中的狀態的唯一途徑就是顯式地提交 (commit) mutation。這樣使得我們可以方便地跟蹤每一個狀態的變化,從而讓我們能夠實現一些工具幫助我們更好地了解我們的應用。
Vue.use(Vuex);
const store = new Vuex.Store({// 數據狀態state {...},// 更改狀態 store.commitmutations: {...},// 類似于mutation(不能直接變更狀態,可以異步操作) store.dispatchactions: {...},// 派生狀態(如,過濾、計數)getters: {...}
})// 將狀態從根組件“注入”到每一個子組件中,且子組件能通過 this.$store 訪問到。
const app = new Vue({el: '#app',store,data() {}
});
?

四、State

  Vuex 使用單一狀態樹,這可以讓我們能夠直接地定位任一特定的狀態片段,在調試的過程中也能輕易地取得整個當前應用狀態的快照。需要注意,單狀態樹和模塊化并不沖突!

  由于 store 中的狀態是響應式的,在組件中調用 store 中的狀態簡單到僅需要在計算屬性中返回即可。

computed: {count () {return store.state.count // this.$store.state.count}
}

  mapState 輔助函數

  當一個組件需要獲取多個狀態時候,將這些狀態都聲明為計算屬性會有些重復和冗余。為了解決這個問題,我們可以使用?mapState?輔助函數幫助我們生成計算屬性。

import { mapState } from 'vuex'computed: mapState({// 映射 this.count 為 store.state.count'count',// 箭頭函數可使代碼更簡練count: state => state.count,// 傳字符串參數 'count' 等同于 `state => state.count`countAlias: 'count',// 為了能夠使用 `this` 獲取局部狀態,必須使用常規函數countPlusLocalState (state) {return state.count + this.localCount},// 使用對象展開運算符將此對象混入到外部對象中...mapState({// ...})
})
?

五、Getter

  Getter(state, getters)可以從 store 中的 state 中派生出一些狀態(如,對數據進行過濾操作)。對于多個組件需要用同一屬性時,意義重大!類似于計算屬性,getter 的返回值會根據它的依賴被緩存起來,且只有當它的依賴值發生了改變才會被重新計算。

  完整請參照?https://vuex.vuejs.org/zh-cn/getters.html

六、Mutation

  mutation 必須是同步函數!!!

  更改 Vuex 的 store 中的狀態的唯一方法是提交 mutation

  Vuex 中的 mutation 非常類似于事件:每個 mutation 都有一個字符串的?事件類型 (type)?和 一個?回調函數 (handler)。調用?store.commit(type, payload)?方法來觸發mutations中的相關方法。

mutations: {increment (state, n) {state.count += n}
}store.commit('increment', 10)
?

  注意:Mutation 需遵守 Vue 的響應規則

  • 最好提前在你的 store 中初始化好所有所需屬性

  • 當需要在對象上添加新屬性時,你應該

    • 使用?Vue.set(obj, 'newProp', 123), 或者

    • 以新對象替換老對象。例如,利用 stage-3 的對象展開運算符我們可以這樣寫

state.obj = { ...state.obj, newProp: 123 }

  完整請參照:https://vuex.vuejs.org/zh-cn/mutations.html

七、Action

  Action 類似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接變更狀態。
  • Action 可以包含任意異步操作。
  • 通過?store.dispatch?方法觸發

  組合 Action:store.dispatch?可以處理被觸發的 action 的處理函數返回的 Promise,并且?store.dispatch?仍舊返回 Promise。

actions: {actionA ({ commit }) {return new Promise((resolve, reject) => {setTimeout(() => {commit('someMutation')resolve()}, 1000)})}
}
//現在你可以:
store.dispatch('actionA').then(() => {// ...
})

?

?

  在另外一個 action 中也可以:

// 假設 getData() 和 getOtherData() 返回的是 Promise
actions: {async actionA ({ commit }) {commit('gotData', await getData())},async actionB ({ dispatch, commit }) {await dispatch('actionA') // 等待 actionA 完成commit('gotOtherData', await getOtherData())}
}
?

  一個?store.dispatch?在不同模塊中可以觸發多個 action 函數。在這種情況下,只有當所有觸發函數完成后,返回的 Promise 才會執行。

  完整請參照:https://vuex.vuejs.org/zh-cn/actions.html

八、Module

  由于使用單一狀態樹,應用的所有狀態會集中到一個比較大的對象。為了解決以上問題,Vuex 允許我們將 store 分割成模塊(module)

  默認情況下,模塊內部的 action、mutation 和 getter 是注冊在全局命名空間的——這樣使得多個模塊能夠對同一 mutation 或 action 作出響應。如果希望你的模塊具有更高的封裝度和復用性,你可以通過添加?namespaced: true?的方式使其成為命名空間模塊當模塊被注冊后,它的所有 getter、action 及 mutation 都會自動根據模塊注冊的路徑調整命名。

九、插件

  Vuex 的 store 接受?plugins?選項,這個選項暴露出每次 mutation 的鉤子。Vuex 插件就是一個函數,它接收 store 作為唯一參數。

const myPlugin = store => {// 當 store 初始化后調用store.subscribe((mutation, state) => {// 每次 mutation 之后調用// mutation 的格式為 { type, payload }})
}
?

  然后像這樣使用:

const store = new Vuex.Store({// ...plugins: [myPlugin]
})

  項目中我們會使用plugin來初始化一些數據

const initActionList = ['base/' + INIT_BUSINESS_SYSTEM_LIST,'threat/' + INIT_STD_COEFFICIENT_LIST
]
export default function (store) {for (let action of initActionList) {Bus.$once(action, () => {store.dispatch(action)})}
}
?

  但是 ,使用plugin的Bus.$once去初始化請求,而不再每個使用模塊自身dispatch。會有解決不掉的兩個問題:

  • 點擊某個按鈕觸發相關數據($once只適合初始化時請求)
  • 某請求依賴store中的情況(刷新)await dispatch('actionA') // 等待 actionA 完成

十、表單處理

  當在嚴格模式中使用 Vuex 時,在屬于 Vuex 的 state 上使用?v-model?會比較棘手

<input v-model="obj.message">

  在用戶輸入時,v-model?會試圖直接修改?obj.message。在嚴格模式中,由于這個修改不是在 mutation 函數中執行的, 這里會拋出一個錯誤。使用傳統的value+input事件實現,但是比較啰嗦。

<input :value="message" @input="updateMessage">computed: {...mapState({message: state => state.obj.message})
},
methods: {updateMessage (e) {this.$store.commit('updateMessage', e.target.value)}
}

  這里,可以使用雙向綁定的計算屬性

computed: {message: {get () {return this.$store.state.obj.message},set (value) {this.$store.commit('updateMessage', value)}}
}

  總結:使用 Vuex 并不意味著你需要將所有的狀態放入 Vuex。雖然將所有的狀態放到 Vuex 會使狀態變化更顯式和易調試,但也會使代碼變得冗長和不直觀。如果有些狀態嚴格屬于單個組件,最好還是作為組件的局部狀態。你應該根據你的應用開發需要進行權衡和確定。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/249211.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/249211.shtml
英文地址,請注明出處:http://en.pswp.cn/news/249211.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Gym 101982 (2018-2019 ACM-ICPC Pacific Northwest Regional Contest (Div. 1) )

傳送門&#xff1a; Problem A 溫暖的簽到題 #include<bits/stdc.h> using namespace std; const int maxn1007; char s1[maxn],s2[maxn]; int main(){ios::sync_with_stdio(false);cin.tie(0);int n,k,sum00,sum10;cin>>k>>s1>>s2;nstrlen(s1);for (i…

day02 while循環 運算符 格式化輸出 編碼

今日主要內容 while循環:判斷條件是否成立。 如果成立執行循環體。然后再次判斷條件&#xff0c;。。。。。直到條件不成立的時候跳出循環 語法&#xff1a; while 條件:   循環體 else:   當條件不成立的時候執行這里 和break沒關系 break 終止當前循環 continue 停止當前…

Bootstrap中文文檔

https://v3.bootcss.com/css/

Mac OS Git 安裝

一、Git是一個分布式的代碼版本管理工具。類似的常用工具還有SVN,CVS。最大的特點也是優點在于提供分布式的代碼管理 1、分支代碼只有一份&#xff01; 使用過svn的童鞋想必都知道&#xff0c;當我們要開發一個新功能或者增加一個新版本或者修改一個復雜bug的時候&#xff0c…

kubeadm安裝k8s 1.13版本

一&#xff1a;環境初始化 1.關閉selinux,iptables 2.做好本地的dns解析&#xff0c;我這里用的是/etc/hosts 3.做一下免密傳輸 4. master:10.0.18.210 node1:10.0.18.211 node2:10.0.18.212 二&#xff1a;配置yum源 [rootmaster yum.repos.d]# vim kuberbetes.repo [kubernet…

MyBastis 三種批量插入方式的性能比較

數據庫使用的是MySQL&#xff0c;JDK版本1.8&#xff0c;運行在SpringBoot環境下 本文章源代碼&#xff1a;https://github.com/runbeyondmove/mybatis-batch-demo 對比3種可用的方式 1、反復執行單條插入語句2、xml拼接sql3、批處理執行 先說結論&#xff1a;少量插入請使用反…

JS對象與jQuery對象

JS對象大致可以分為三種&#xff0c;如下圖&#xff1a; JS常用內置對象&#xff08;JS自身所持有的對象&#xff0c;不需要創建&#xff0c;直接可用&#xff09;&#xff1a; String&#xff1a;API跟java的字符串API大致相同 兩種創建對象的方式&#xff1a;String s1 “…

Vue-router 中hash模式和history模式的區別

Vue-router 中hash模式和history模式的關系 在vue的路由配置中有mode選項 最直觀的區別就是在url中 hash 帶了一個很丑的 # 而history是沒有#的 mode:"hash"; mode:"history"; hash模式和history模式的不同 對于vue這類漸進式前端開發框架&#xff0…

Nginx Slab內存管理

L38 Slub內存管理適用 ngx_http_limit_conn_module、ngx_http_limit_req_module 模塊場景 我們可以用阿里第三方模塊Slab_Stat模塊 并且用add-module 方式編譯進openresty中 轉載于:https://www.cnblogs.com/jackey2015/p/10684151.html

day2---while else

# -*- coding:utf-8 -*-while 條件&#xff1a;循環體終止循環 else&#xff1a; while else 解釋&#xff1a;當循環體中沒有被break打斷則會運行else&#xff0c;打斷則不會運行else# 例子 a 0 while a < 5:print(a)a 1break else:print(循環結束) # 0 轉載于:https:/…

jQuery中this與$(this)的區別總結

https://www.cnblogs.com/gfl123/p/8080484.html

2019前端必會黑科技之PWA

一、背景 從2018年到現在&#xff0c;作為號稱下一代web應用模型的PWA&#xff0c;逐漸成為了一個各大前端廠商爭先恐后進行涉足&#xff0c;布局的一個新的技術&#xff0c; 其主要的對標物Native app&#xff0c;作為現在最主流的mobile端應用&#xff0c;它的安全&#xff…

Tcpdump抓包工具的使用

# Tcpdump抓包工具的使用## 簡介tcpdump是linux下最常用的命令行抓包工具&#xff0c;可以在線安裝## 安裝- sudo apt install tcpdump## 查看網卡- ip addr查看網卡名稱## 簡單的使用示例- sudo tcpdump -i enp032 抓取指定網卡的數據包&#xff0c;并- sudo tcpdump -i enp03…

Node.js異步庫async

async的使用需要安裝第三方包 1.串行無關聯 async.series 函數依次執行,后面不需要調前面步驟的結果 程序執行時間為所有步驟之和 2.并行無關聯 async.paraller 某步出錯不影響其他步驟執行 程序執行時間為最長的那個時間 3.串行有關聯 async.waterfall 函數依次執行,后面需要…

Java技術棧---語言基礎

基礎語法 面向對象 接口 容器 異常 泛型 反射 注解 I/O

Mongodb 查詢時間類型

$where: this.CreateDate.toJSON().slice(0,13) "2019-04-04T05"轉載于:https://www.cnblogs.com/kevin1988/p/10685075.html

vue prop不同數據類型(數組,對象..)設置默認值

vue prop 會接收不同的數據類型&#xff0c;這里列出了 常用的數據類型的設置默認值的寫法,其中包含&#xff1a; Number, String, Boolean, Array, Function, Object refAge: { type: Number, default: 0 }, refName: { type: String, default: }, hotDataLoading: { typ…

正則表達式——基礎

正則表達式的基本符號使用&#xff1a; 1。基本符號&#xff1a; a . 匹配任意單個字符&#xff0c;如&#xff1a;.000就可以匹配到1000&#xff0c;2000&#xff0c;3000&#xff0c;a000,b000等。 b | 匹配滿足其中一個條件&#xff0c;如&#xff1a; 1000|2000|3000 可以…

談一談并查集QAQ(上)

最近幾日理了理學過的很多oi知識。。。發現不知不覺就有很多的知識忘記了。。。 在聊聊并查集的時候順便當作鞏固吧。。。。 什么是并查集呢? ( Union Find Set ) 是一種用于處理分離集合的抽象數據結構類型。 具體一點: 當我們給出兩個元素的一個無序對&#xff08;a,b&#…

vue的雙向綁定原理及實現

前言 使用vue也好有一段時間了&#xff0c;雖然對其雙向綁定原理也有了解個大概&#xff0c;但也沒好好探究下其原理實現&#xff0c;所以這次特意花了幾晚時間查閱資料和閱讀相關源碼&#xff0c;自己也實現一個簡單版vue的雙向綁定版本&#xff0c;先上個成果圖來吸引各位&a…