Vuex是什麼?執行原理是什麼?
Vuex 是一個專為 Vue.js 應用程式開發的狀態管理模式。它採用集中式儲存管理應用的所有元件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。
在View通過Dispatch觸底Action,Action觸發Mutation,最後更新State觸發View更新,這一流程遵循單向資料流的原則。
圖來自Vuex官網?
Vuex的簡單定義和用法
import Vuex from 'Vuex'
import Vue from 'vue'
Vue.use(Vuex)
let store = new Vuex.Store({
state: {
num: 1
},
getters: {
numStore(state) {
return state.num + 1
}
},
mutations: {
addOne(state, params) {
state.num = state.num + params.num
}
},
actions: {
addOneAsync({ commit }, params) {
setTimeout(() => {
commit('addOne', params)
}, 1000)
}
}
})
export default store
複製程式碼
在View中可以通過this.$store.commit
觸發mutation
,或者通過this.$store.dispatch
觸發action
。這裡不會詳細介紹Vuex
怎麼去使用,這篇嘮嗑主要講的Vuex
的實現原理,入門的話可以到官網溜一波。
溫馨提示:定義好的Vuex就得在Vue例項引數傳上Vuex例項
new Vue({
store,
render: h => h(App),
}).$mount('#app')
複製程式碼
Vuex的原理是怎麼樣的?六步帶你撕開它神祕的面紗
第一步,初始化Vuex檔案
在自己感覺看著舒服的微信建一個miniVuex.js檔案
複製程式碼
let Vue
class Store{
constructor(options) {}
}
function install(_Vue){
}
export default { Store, install }
複製程式碼
為什麼要定義這Store跟install方法?
Store方法應該大家都很好理解,回想一下Vuex
的用法,是不是上來就給它來一個new Vuex.Store
?然後傳進去一個Object
?
import Vuex from 'Vuex'
let store = new Vuex.Store({})
複製程式碼
再回看自己定義Store
函式,是不是清晰很多了?Store
函式接收一個options實參物件
可能大家對於為什麼要定義install
函式有點困惑(如果開發過Vue外掛,或者熟悉Vue.use()
Api的大佬,請忽略),我們再回想一下當,匯出Vuex
的時候,是不是要Vue.use(Vuex)
一下?
import Vuex from 'Vuex'
Vue.use(Vuex)
複製程式碼
因為當Vue.use(Vuex)
Api的時候,Vue.use
會將呼叫外掛(這裡是Vuex)
的install
函式,然後將Vue
傳進去,並可以在install
函式裡通過this
可以訪問Vue例項
。所以在開發外掛的時候,install
函式是必須要提供的。
第二步,實現install方法
在Vuex
中install
函式,主要是拿到Vue
儲存起來,然後,通過Vue.mixin
混入將store
掛載到Vue.prototype
上;至於平時在頁面上我們為什麼能通過this.$store
訪問Vuex
例項,就是在這裡混入進去的;至於使用Vue.mixin
混入來掛載Vuex例項
到Vue.prototype
,主要是因為,我只想在new Vue
的時候只在beforeCreate
鉤子裡掛載一次就ok,不想每個頁面都去重新掛載一次。
具體程式碼如下?
let Vue
class Store {
constructor(options) {}
}
// 新增install實現
function install(_Vue) {
Vue = _Vue
Vue.mixin({
beforeCreate() {
if (this.$options.store) {
Vue.prototype.$store = this.$options.store
}
}
})
}
export default { Store, install }
複製程式碼
第三步,實現state的雙向繫結
實現staet
的雙向繫結是件非常簡單的事,我們只需要利用Vue
自身的雙向繫結機制就就可以實現;我們主要將new Vuex.Store({state:{}})
存放在一個new Vue 例項
上就可以。之所以Vuex官網說Vuex 是一個專為 Vue.js 應用程式開發的狀態管理模式,就是因為Vuex
內部實現雙向繫結的時候,使用的是Vue
自身的雙向繫結機制,將Vue
強強的綁在身上。
let Vue
class Store {
constructor(options) {
//新增程式碼
this.state = new Vue({
data: options.state && options.state || {}
})
}
}
function install(_Vue) {
Vue = _Vue
Vue.mixin({
beforeCreate() {
if (this.$options.store) {
Vue.prototype.$store = this.$options.store
}
}
})
}
export default { Store, install }
複製程式碼
第四步,實現mutations和commit
實現mutations
只要是將傳進來的mutations
儲存到例項就行,如果不傳就預設為一個空物件;在實現commite
之前,先來看看commit
的用法。
this.$store.commit(type, params)
複製程式碼
commit
主要是將傳進來的type
,找到對應的mutations
裡面的函式,進行觸發,並將this.state
傳給它的一個引數(因為在定義mutations的時候是不是(可以引數下面第一段示例程式碼)在第一個引數可以訪問state裡面的資料?至於為什麼可以訪問,就是在這個時候傳進去的),第二個引數才是額外的引數。
mutations定義示例程式碼
mutations: {
addOne(state, params) {
state.num = state.num + params.num
}
}
複製程式碼
具體程式碼如下?
let Vue
class Store {
constructor(options) {
this.state = new Vue({
data: options.state && options.state || {}
})
//新增程式碼
this.mutations = options.mutations && options.mutations || {}
}
// 新增程式碼
commit = (type, params) => {
this.mutations[type]&&this.mutations[type](this.state, params)
}
}
function install(_Vue) {
Vue = _Vue
Vue.mixin({
beforeCreate() {
if (this.$options.store) {
Vue.prototype.$store = this.$options.store
}
}
})
}
export default { Store, install }
複製程式碼
至於commit
為什麼要使用箭頭函式,這裡做一個解釋,因為在actions裡面異地再提交一下commit(如下面示例程式碼),那麼會導致this中的上下文產生變化,不再指向Store例項就報一個mutations of undefined的錯誤(如下面圖片);為了避免這種情況出現,使用了箭頭函式。
示例程式碼
actions: {
addOneAsync({ commit }, params) {
setTimeout(() => {
commit('addOne', params)
}, 1000)
}
}
複製程式碼
報錯提示
第五步,實現getters
getters
的原理,也不難理解,但是實現就要手動通過(Object.defineProperty)去監聽,它的那個getter
別使用了,再觸發對應的getter
,getters
是隻讀,所以在Object.defineProperty監聽的時候,只需要提供get
(有傳的前提在才會進行Object.defineProperty監聽,不傳的話,什麼也不敢),然後把this.state
傳給它的一個引數(因為在定義getter的時候,可以通過第一個引數訪問state,可參考下面的示例)。
溫馨提示:上面的getters是指整個大的getters,getter是指的getters裡面小的各個鍵值對(比如下面示例中的numStore),我怕有同學會不知道,還是提一下
定義getters示例
getters: {
numStore(state) {
return state.num + 1
}
}
複製程式碼
具體實現程式碼?
let Vue
class Store {
constructor(options) {
this.state = new Vue({
data: options.state && options.state || {}
})
this.mutations = options.mutations && options.mutations || {}
//新增程式碼
options.getters && this.initGetters(options.getters)
}
//新增程式碼
initGetters(getters) {
this.getters = {}
Object.keys(getters).forEach(key => {
Object.defineProperty(this.getters, key, {
get: () => {
return getters[key](this.state)
}
})
})
}
commit = (type, params) => {
this.mutations[type]&&this.mutations[type](this.state, params)
}
}
function install(_Vue) {
Vue = _Vue
Vue.mixin({
beforeCreate() {
if (this.$options.store) {
Vue.prototype.$store = this.$options.store
}
}
})
}
export default { Store, install }
複製程式碼
第六步,實現actions和dispatch
actions
和dispatch
的實現跟mutations
和commit
非常類似;實現actions
只要是將傳進來的actions
儲存到例項就行,如果不傳就預設為一個空物件;在實現dispatch
之前,先來看看dispatch
的用法。
this.$store.dispacth(type, params)
複製程式碼
dispacth
主要是將傳進來的type
,找到對應的actions
裡面的函式,進行觸發,並將一個Object(裡面包含commit,dispatch,state)
傳給它的一個引數(因為在定義actions的時候是不是在第一個引數可以訪問這些(commit,dispatch,state...可以引數下面第一段示例程式碼)?至於為什麼可以訪問,就是在這個時候傳進去的),第二個引數才是額外的引數。
示例程式碼
actions: {
addOneAsync({ commit,dispatch,state }, params) {
setTimeout(() => {
commit('addOne', params)
}, 1000)
}
}
複製程式碼
具體實現程式碼?
let Vue
class Store {
constructor(options) {
this.state = new Vue({
data: options.state && options.state || {}
})
this.mutations = options.mutations && options.mutations || {}
//新增程式碼
this.actions = options.actions && options.actions || {}
options.getters && this.initGetters(options.getters)
}
initGetters(getters) {
this.getters = {}
Object.keys(getters).forEach(key => {
Object.defineProperty(this.getters, key, {
get: () => {
return getters[key](this.state)
}
})
})
}
commit = (type, params) => {
this.mutations[type](this.state, params)
}
//新增程式碼
dispatch(type, params) {
this.actions[type] && this.actions[type]({
commit: this.commit,
state: this.state,
dispatch: this.dispatch
}, params)
}
}
function install(_Vue) {
Vue = _Vue
Vue.mixin({
beforeCreate() {
if (this.$options.store) {
Vue.prototype.$store = this.$options.store
}
}
})
}
export default { Store, install }
複製程式碼
好了,以上那段也是整個miniVuex
的完整程式碼了,裡面我們實現了state,getters,mutations,actions,commit,dispatch
;至於怎麼使用,就跟之前怎麼用Vuex一樣,把import的路徑換成我們自己的miniVuex路徑
使用例子:
import Vuex from './miniVuex'
import Vue from 'vue'
Vue.use(Vuex)
let store = new Vuex.Store({
state: {},
getters: {},
mutations:{},
actions: {}
})
export default store
複製程式碼
如果,你每一步都看懂了,你還怕面試官問你Vuex的原理?還怕他讓你手寫?還害怕逼逼不贏他?
有錯誤的地方,歡迎大佬指出;有解釋不夠充分的地方,歡迎大佬補充;有更好的改進方法,歡迎大佬提供,一起交流交流...