你不知道action與mutation怎麼被呼叫的?趕緊回去看啊Vuex原始碼學習(七)action和mutation如何被呼叫的(呼叫篇))
上兩個小節已經講述了commit與dispatch如何呼叫mutation與action的,但是action中有幾個引數感覺涉及到了一些我們遺漏(故意不講)的點。
模組的context
在installModule的時候 給每個模組繫結了一個屬性context。 通過makeLocalContext函式建立的,在註冊action、mutation和getters都有使用。這個context是什麼呢?
makeLocalContext函式建立了一個什麼東西
返回值local物件 由兩個方法、兩個屬性構成的。 這個目的是什麼?建立區域性模組的dispatch、commit、getters、state 也就是這個東西我們按照型別分析
- dispatch與commit
// 檢視全名,如果沒有全名 可能是根模組或者沒有設定名稱空間
const noNamespace = namespace === '';
// 如果沒有全名 就使用全域性(store)上的disptach
// 有全名的話 構建一個新的dispatch
// 這個新的dispatch仍然接收三個引數(與store上的dispatch一樣)
//
dispatch: noNamespace ? store.dispatch : (_type, _payload, _options) => {
//unifyObjectStyle 對額外傳入的_options沒有任何處理 只是確定一下位置
const args = unifyObjectStyle(_type, _payload, _options)
// options 值沒有發生變化
const { payload, options } = args
let { type } = args
// 在disptach的時候是否指定選擇root(根)
// 如果options設定為{root : true} 那麼就會跳過下面
if (!options || !options.root) {
// 拼接真正的名字
type = namespace + type
if (process.env.NODE_ENV !== 'production' && !store._actions[type]) {
console.error(`[vuex] unknown local action type: ${args.type}, global type: ${type}`)
return
}
}
// 呼叫(補全名字後)的action
return store.dispatch(type, payload)
},
複製程式碼
這段程式碼我們可以看出來,local物件(也就是模組的context屬性)中的dispacth會在未指定使用根模組名字時,會把dispatch呼叫的名字強行加上這個模組的全名,用這個dispatch呼叫的action都會變成你這個模組下的action
所以local中的dispatch與store中的disptach有什麼不同
通俗的講 我們想要呼叫A模組(有名稱空間的某個action B)需要做的是
this.$store.dispatch('A模組的全名/B的名字');
複製程式碼
在A模組的action中想要使用dispatch來做一些事情。
actions.js
export const ajaxGetUserName = ({dispatch})=>{
// 這個時候用dispatch呼叫自己模組內的其餘的action不需要加上全名
dispatch('ajaxGetUserAge');
// 想要變成和根模組一樣的dispatch 需要加上一個options註明{root : true}
// 這個時候dispatch就會變成全域性的 不會主動幫你拼接全名了
}
export const ajaxGetUserAge = () => {
// do something
}
複製程式碼
同理local物件下的commit也是做了同樣的事情,
這裡就不多加解釋了,相信聰明的你早就可以舉一反三了。兩個方法說完了,下面該講兩個屬性了
- getters與state
這兩個屬性就是我們的getters與state,但是這是我們local物件中,也就是區域性模組下的getters與state。getters與state如何建立的 getters 首先判斷全名是不是為空,為空就返回store物件的getters,有的話就建立區域性getters。與其說是建立不如說是代理
如何建立區域性的getters? 代理的方式
makeLocalGetters原始碼
function makeLocalGetters (store, namespace) {
// 設計思想
//其實我們並不需要建立一套getters,
// 只要我們在local中通過getters來獲取一些區域性模組的值的時候,
// 可以被代理到真正存放這些getters的地方。
// 建立代理物件
const gettersProxy = {}
// 找到切割點
const splitPos = namespace.length
Object.keys(store.getters).forEach(type => {
// skip if the target getter is not match this namespace
// 得去getters裡面找一下有沒有這個namespace為字首的getter。
// 沒有就找不到了
if (type.slice(0, splitPos) !== namespace) return
// extract local getter type
// 拿到模組內註冊的那個區域性的getter名字
// 全名是set/getName
// localType就是getName
const localType = type.slice(splitPos)
// Add a port to the getters proxy.
// Define as getter property because
// we do not want to evaluate the getters in this time.
// 完成代理任務,
// 在查詢區域性名字是被代理到對應的store.getters中的(全名)getter
Object.defineProperty(gettersProxy, localType, {
get: () => store.getters[type],
enumerable: true
})
})
//返回代理物件
return gettersProxy
}
複製程式碼
建立區域性的getters就是一個代理的過程,在使用模組內使用(沒有加上名稱空間的)getters的名字,會被代理到,store例項上那個真正的(全名的)getters。
state 這個相對來說就簡單很多了
與代理類似,只是state只需要代理到state中對應那個模組的state,這個就比較簡單了。建立完畢
context是如何被建立的大家已經比較瞭解了。context的作用是什麼? (local就是contenxt)之前說過註冊mutation、action、getters都用到了local。用他們幹什麼?一一介紹
1. 註冊mutation
我們註冊的mutation在被commit呼叫時,使用的state是區域性的state,當前模組內的state,所以不用特殊方式mutation無法更新父(祖先)模組和兄弟模組的內容。2. 註冊dispatch
dispatch是可以呼叫到模組內的mutation、disptach,也就是說它有更新模組內資料的能力,但是隻給了dispatch傳入了store的getters與state(雖然有了這倆你想要什麼放在vuex的資料都能得到),並沒有給store的dispatch與mutation。
這就說名dispatch可以檢視store中的所有資料,你放在vuex裡面的資料我都可以看,但是你想改不使用特殊手段,不好意思只能改自己模組的。
3. 註冊getters
getters並沒有改變資料的能力,你願意怎麼運算元據都可以,模組內的資料,全模組的資料都可以給你,你願意怎麼計算都可以。在註冊中我們可以看到,vuex對這個改變資料的許可權控制的很嚴格,但是檢視資料控制的很鬆,改只能改自己模組的,查你願意怎麼看都OK。
總結
- context(也是local)是經過一個makeLocalContext的函式建立的,裡面有區域性的dispatch、commit方法和getters、state屬性。
- 區域性的方法屬性都是隻能訪問區域性模組內的,除非在使用時額外傳入options(
{root:true}
)來解開區域性模組的限制。 - 區域性的getters是通過makeLocalGetters來實現的,主要思想是依靠代理的方式,把區域性的名字的getter代理到store的getters中那個全名的getter。
- context 的作用可以幫助dispatch與commit控制更新資料的許可權,幫助模組內getters拿到區域性與全模組的資料。
這個章節結束,我們所有和模組有關的內容就已經完結了。 對於模組做一個小的總結。
模組的意義
- 模組與模組連結把Vuex初始化傳入的內容,整理成一個方便處理的模組樹(方便)
- 模組讓action、mutation、getters、state都有了自己的全名(設定namespaced為true),起名字不再被約束,減少了命名衝突。
- 模組還給action、mutation、getters提供了區域性上下文(context)讓模組內的這些方法和屬性,可以方便的修改模組內的資料以及獲取全模組與模組內的資料。
- dispatch與commit也對模組進行了全力的支援(不支援不白做了嗎),
所以模組為Vuex提供了很多方便,方便的去獲取資料、修改資料。那麼Vuex真正的資料倉儲在哪裡?資料都儲存在哪裡? 我們下一章見