Vuex相當於一個商店,你可以在商店上架各種各樣的商品,專案中的元件就相當於買家,他們可以購買商店中的任何商品,當一個元件買走了某樣商品,那麼商店中該樣商品的數量就會減少一個。
Vuex有五個核心概念,State,Getter,Mutations,Actions和Module。State,Getter和Mutations是必須的,它們的關係官網有一張圖能非常清晰的說明:
- State(狀態資料屬性,資料驅動檢視)
- Getters(獲取狀態中儲存的值)
- Mutations(修改狀態的唯一方法就是mutations,但mutations中的方法是同步的)
- Actions(Actions中方法是非同步的,元件中通過dispatch觸發Actions,在Actions中commit觸發mutations,然後修改State)
- Module(分塊管理相關狀態)
上圖流程是這樣的,你在State中宣告瞭一個資料屬性,在某個元件中引用了它,那麼它就會被渲染render到這個元件,當這個元件想非同步的修改這個State值時,它就需要想Actions分發dispatch某個方法,在Actions非同步的觸發commit Mutations中的某個方法,而只有Mutations中的被觸發的這個方法才能修改State的值。
State
在State中定義了一個count屬性,之後這個count可以被專案中任意的元件所使用。
state: {
count: 1,
}
複製程式碼
獲取State屬性的方法有三種,第一種通過this.$store訪問,後兩種都是通過vuex提供的輔助函式mapState,使用它之前需要從vuex中匯入。因為State中的屬性是響應式的,從store例項中讀取狀態最簡單的方法就是在計算屬性中返回某個狀態。
第一種方式:通過每個元件擁有的$store訪問
computed:{
count(){
return this.$store.state.count
}
}
複製程式碼
第二種方式,通過mapState訪問
import {mapState} from 'vuex'
computed:mapState{
//1.箭頭函式
count: state => state.count,
//2.傳字串引數‘count’等同於state => state.count,counAlisa是別名,之前的都可以起別名
countAlisa:'count',
//3.傳一個函式,在顯示count值之前,還能在元件內做一些其他操作
countLocalState(state){
return state.count + this.num;
}
}
//當計算屬性的方法名與state中屬性名同名時,就可以這樣簡寫
computed: mapState([
'count'
])
複製程式碼
第三種方式,物件的展開運算子,目的是將它與區域性計算屬性混合使用
computed:{
...mapState({
//這裡的操作與第二種方式是一樣的
count:state => state.count,
countAlisa:'count',
countLocalState(state){
return state.count + this.num;
}
})
}
//當計算屬性的方法名與state中屬性名同名時,就可以這樣簡寫
computed:{
...mapState([
'count',
'msg'
])
},
複製程式碼
Getters
可以認為是 store 的計算屬性,可以對State中的資料做一些過濾,計算長度。在state中定義一個list列表。
state: {
lists: [
{ id: 1, msg: "hi1" },
{ id: 2, msg: "hi2" },
{ id: 3, msg: "hi3" },
{ id: 4, msg: "hi4" },
{ id: 5, msg: "hi5" }
]
}
getters{
//引數為state,通過屬性訪問
listLength: state =>{
return state.lists.length;
}
listFilter(state){
return state.lists.filter(item => item.id < 4);
}
//第二個引數還可以傳getters
listFilterLength: (state, getters) => {
return getters.listFilter.length
}
//通過函式訪問
getListById: (state) => (id) => {
return state.todos.find(item => item.id === id)
}
}
複製程式碼
在元件中訪問getters基本上與state相似,這裡不過多贅述,可以參考vuex官方文件。
computed:{
listLength(){
return this.$store.getters.listLength
},
getListById(){
return this.$store.getters.getListById(2);
}
複製程式碼
import { mapGetters } from 'vuex'
computed: {
// 使用物件展開運算子將 getter 混入 computed 物件中
...mapGetters([
'listLength',
'listFilterLength',
])
}
複製程式碼
Mutations
Mutations是改變State的唯一方法,但是它的方法必須是同步的,如果有非同步操作,那麼在stata中的資料可能和檢視中的數值不同。
mutations: {
addNum(state, num) {
state.count += num;
},
//在mutations中做非同步,在stata中的資料可能和檢視中的數值不同,payload為載荷,此方式為錯誤示範
addCountByasync(state, payload) {
setTimeout(() => {
state.count += payload.num;
}, 1000)
},
addCountByasync2(state, num) {
state.count += num;
}
},
複製程式碼
在元件內通過methods方法提交,也是有$store方式和輔助函式的方式:
methods{
addCountByasync(){
//1.第一個引數是事件的名字,第二個引數是傳遞的資料
this.$store.commit('addCountByasync', {num: 5})
//以物件方式提交
this.$store.commit({
type:'addCountByasync',
num:5
})
},
}
複製程式碼
以下的輔助函式訪問方式參考vuex的官方文件
import { mapMutations } from 'vuex'
export default {
// ...
methods: {
...mapMutations([
'increment', // 將 `this.increment()` 對映為 `this.$store.commit('increment')`
// `mapMutations` 也支援載荷:
'incrementBy' // 將 `this.incrementBy(amount)` 對映為 `this.$store.commit('incrementBy', amount)`
]),
...mapMutations({
add: 'increment' // 將 `this.add()` 對映為 `this.$store.commit('increment')`
})
}
}
複製程式碼
Actions
Actions的方法就是為了解決Mutations中不能做非同步操作的問題,所有的非同步操作放在Actions裡面,只在Mutations中修改State的值。現在元件中dispatch Actions,Actions commit Mutations。
mutations: {
addCountByasync2(state, num) {
state.count += num;
}
}
actions: {
addCountByasync({ commit }, payload) {
setTimeout(() => {
commit('addCountByasync2', payload.num)
}, 1000)
}
}
複製程式碼
在元件內的methods中分發:
methods:{
addCountByasync2(){
this.$store.dispatch('addCountByasync', {num: 5})
}
}
複製程式碼
Modules
就是根據資料的業務型別分為幾個模組,每個模組都有上述的四種物件,通過模組來呼叫,模組的用法請參考vuex手冊。
vuex開發中遇到的坑
在給State中的某個資料物件新增新屬性時,無法更新到檢視,需要手動設定,使得資料可以驅動檢視。所以最好我們在Store中初始化好屬性,不要臨時新增。
state: {
myProp: {
}
},
getters: {
myProp: (state) => {
return state.myProp;
}
},
mutations: {
changeStateProp(state, name) {
//這樣修改資料檢視是無法更新的
// state.myProp.name = name;
//手動設定,給State中的資料物件新增新屬性
Vue.set(state.myProp, 'name', name)
}
},
actions: {
changeStateProp({ commit }, payload) {
commit('changeStateProp', payload.name);
}
}
複製程式碼
某個元件內:
<h2>{{ myProp }}</h2>
<button @click="changeStateProp">修改state資料</button>
computed:{
myProp(){
return this.$store.getters.myProp
}
},
methods: {
changeStateProp(){
this.$store.dispatch('changeStateProp', {name:'kitty'});
}
}
複製程式碼
總結
官網上有一段話,用來做總結:
如果您不打算開發大型單頁應用,使用 Vuex 可能是繁瑣冗餘的。確實是如此——如果您的應用夠簡單,您最好不要使用 Vuex。一個簡單的 store 模式就足夠您所需了。但是,如果您需要構建一箇中大型單頁應用,您很可能會考慮如何更好地在元件外部管理狀態,Vuex 將會成為自然而然的選擇。
該筆記是聽完某視訊vue老師講的課程之後做的筆記,如有侵權,請告知。