一、vuex 的 state 如何保證其響應式
vuex 的 store對象的 state 是響應式的,凡是預先在 state 中定義的狀態,都會被加入到響應式系統中,當狀態發生了變化,所有引用狀態的 vue 文件的 template 都會隨之發生變化,做到響應式的功能。
但是其前提是:提前定義好的會被加入到響應式系統中,那后面追加的屬性或對象能不能加入到響應式系統中呢?
答案是:不能,但是,如果按照指定的方式來添加和刪除屬性,是可以做到響應式的。
比如現在我要添加一個新屬性 height,用兩種方式添加,如下:
1、方式1:此種方式能添加 state 中對象的屬性,但無法加入到響應式系統中,即頁面上不會顯示出來,實際上確實存在了這個屬性
mutations: { addheight(state){ state.stus[0]['height'] = 168 } }
2、方式2:此方式可以讓屬性加入到響應式系統中
mutations: { addheight(state){ Vue.set(state.stus[1],'height',178) //參數一為對象,參數二為key,參數為value
} }
3、方式3:用新對象給舊對象重新賦值(下面會介紹到)
4、說完添加屬性,再說下刪除吧,想要刪除屬性並加入響應式系統,如下方式:
mutations: { delheight(state){ Vue.delete(state.stus[1],'height') //參數一為對象,參數二是key
} }
5、總結:
(1)Vuex 的 store 對象中的 state 是響應式的,當 state 中的數據發生改變時,vue 組件會自動更新。
(2)但是它有一個前提條件,與我們之前了解的響應式前提是一致的,就是需要:提前在 state 中定義好所需的初始化屬性。動態添加的屬性是不能響應式的。
(3)如何保證動態添加的屬性的響應式呢 - 有一下兩種方式
方式一:使用 Vue.set(obj, key, value)
方式二:使用新對象給舊對象重新賦值
(4)在state刪除已經存在的屬性,使用 delete + 屬性滿足不了響應式,必須這樣使用:Vue.delete(obj, 屬性名)
二、解決 computed 監聽 vuex 中 state 對象屬性不生效的問題
首先我們需要了解一個前提基礎:
computed 屬性監聽對象時候,若對象的引用地址未改變,那么computed將不會檢測到。
比如object中的某個key對應的value發生了變化,computed檢測不出來
// 原寫法
export default { namespaced: true, state: { info:{ other: {} } }, mutations: { addInformation(state,info){ let data = Object.assign(state.info, info); //此時 state.info 的值改變了,但是引用地址沒變
state.shareInformation = data; }, } }
使用 Object.assign() 的目標對象仍然是 state.info ,所以雖然其值變了,但是引用地址是沒變的,所以 computed 檢測不到。
// 正確寫法
addInformation(state,info){ //創建一個新的對象,將state.info,Info 對象復制到新對象中
let data = Object.assign({},state.info,info); //將 state.info 指向新對象的引用地址
state.info = data; },
使用 Object.assign() 的目標對象是個空對象,將 2 個源對象 state.info、info 的內容復制到新對象上 ,所以其值變了,引用地址也變了。這樣 computed 才可以檢測到。
三、vue 關於 deep watch 監聽不到 vuex state 對象變化的的問題
簡而言之,如果 vuex state 中是一個空對象 {},那么監聽就會有問題,必須得有提前定義好的初始化屬性才可以保證監聽。那么如果無法確定動態添加屬性的 key 是啥,怎么辦呢?先給出解決方案:
// 簡易拷貝
let _reply = JSON.parse(JSON.stringify(state.reply)) // 加入動態屬性 orderId 是變化的
_reply[orderId] = data.orderId
// 更新,只能這樣一波騷操作才能讓computed和watch監聽到。
state.reply = _reply
具體原因其實跟第二章一樣,要保證其引用地址變了才行。