什麼是vuex
先來看官方介紹:
Vuex 是一個專爲 Vue.js 應用程序開發的狀態管理模式。它採用集中式存儲管理應用的所有組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。Vuex 也集成到 Vue 的官方調試工具 devtools extension,提供了諸如零配置的 time-travel 調試、狀態快照導入導出等高級調試功能
vuex是mcv模式中的model層,數據通過 state->components->acticon->mutation,然後改變狀態,在結合雙向綁定實現頁面更新
vue和vuex
先看代碼
new Vuex.Store({
state:{},
mutations:{},
actions:{},
getters:{}
})
new Vue({
data:{},
methods:{},
computed:{}
})
可以看出vue和vuex差不多,
- state->data
- 獲取數據 getters->computed
- 更改數據 mutations-> methods
通過修改mutations方法修改state數據。
說到mutations和actions不得不說commit和dispatch,通過點擊事件觸發methods的方法,當存在異步時,vuex通過dispatch方法觸發actions中的commit來使用mutations中的方法
vuex源碼分析
vuex借鑑了flux和redux等,把數據存放在全局的store中,再將store掛載到vue的組件實例中
vuex的store掛載
- 在vue中安裝vuex
import Vuex from 'vuex';
Vue.use(vuex);// vue的插件機制
- 在vue.use(vuex)時,調用vuex的install方法
export function install (_Vue) {
if (Vue && _Vue === Vue) {
if (process.env.NODE_ENV !== 'production') {
console.error(
'[vuex] already installed. Vue.use(Vuex) should be called only once.'
)
}
return
}
Vue = _Vue
applyMixin(Vue)
}
- applyMixin方法,在vue生命週期beforeCreate鉤子函數前混入vuexInit方法
Vue.mixin({ beforeCreate: vuexInit });
function vuexInit () {
const options = this.$options
// store injection
if (options.store) {
this.$store = typeof options.store === 'function'
? options.store()
: options.store
} else if (options.parent && options.parent.$store) {
this.$store = options.parent.$store
}
}
這步使用vue的mixin混入,實現store注入vue組件實例,註冊vuex的store屬性($store)
vuex中state和getters如何映射組件中更新
- vuex源碼中resetStoreVM方法
function resetStoreVM (store, state, hot) {
const oldVm = store._vm
// 設置 getters 屬性
store.getters = {}
const wrappedGetters = store._wrappedGetters
const computed = {}
// 遍歷 wrappedGetters 屬性
forEachValue(wrappedGetters, (fn, key) => {
// 給 computed 對象添加屬性
computed[key] = partial(fn, store)
// 重寫 get 方法
// store.getters.xx 其實是訪問了store._vm[xx],其中添加 computed 屬性
Object.defineProperty(store.getters, key, {
get: () => store._vm[key],
enumerable: true // for local getters
})
})
const silent = Vue.config.silent
Vue.config.silent = true
// 創建Vue實例來保存state,同時讓state變成響應式
// store._vm._data.$$state = store.state
store._vm = new Vue({
data: {
$$state: state
},
computed
})
Vue.config.silent = silent
// 只能通過commit方式更改狀態
if (store.strict) {
enableStrictMode(store)
}
}
可以看出vuex中state借用data,將state存入vue實例中的data,而vuex中的getters借用vue的computed實現數據監聽
vuex中mutations如何更新
registerMutation方法中,獲取store中mutation type函數集合,再將新的函數push進去,再通過原函數傳入state。
// 註冊對應模塊的mutation,供state修改使用
module.forEachMutation((mutation, key) => {
const namespacedType = namespace + key
registerMutation(store, namespacedType, mutation, local)
})
// 註冊對應模塊的action,供數據操作、提交mutation等異步操作使用
module.forEachAction((action, key) => {
const namespacedType = namespace + key
registerAction(store, namespacedType, action, local)
})
// 註冊對應模塊的getters,供state讀取使用
module.forEachGetter((getter, key) => {
const namespacedType = namespace + key
registerGetter(store, namespacedType, getter, local)
})
function registerMutation (store, type, handler, local) {
// 取出對應type的mutations-handler集合
const entry = store._mutations[type] || (store._mutations[type] = [])
// commit實際調用的不是我們傳入的handler,而是經過封裝的
entry.push(function wrappedMutationHandler (payload) {
// 調用handler並將state傳入
handler(local.state, payload)
})
}
爲什麼state只能在mutations中修改
如果不開啓嚴格模式,state可以直接修改
如果使用actions中修改,vuex會給與警報,因爲源碼中action只能有一個聲明,在多個action 中修改,可能會產生異步錯誤。而直接修改也屬於dispatch異步修改,所以官方會給與警告