现在前端开发中vue成为主流框架之一,只要不是很小的项目,使用到的诗句都会引用vuex来进行状态管理。最近新开展的项目比较复杂,使用vuex的地方也比较多。在此过程中也遇到了不少问题,进了不少坑,也爬出了好多坑,再这来给大家分享一下
为什么要使用vuex
在当前前端的模块化项目中不可避免的是某些变量需要在全局范围内引用,此时父子组件的传值,子父组件间的传值,兄弟组件间的传值成了我们需要解决的问题。虽然vue中提供了props(父传子)commit(子传父)兄弟间也可以用localstorage和sessionstorage。(在做项目少的时候用这种方式还是方便的)但是这种方式在数据量大的项目开发中带来的问题(难管理,难维护,代码复杂,安全性低)。vuex的诞生也是为了解决这些问题,从而大大提高我们vue项目的开发效率。我通过一段时间,看了一下源码
vuex的整体架构主体
源码解析(工作原理)
根state的存储位置
const store = new Vuex.Store({
state: { count: 0 },
mutations: { increment (state) {
state.count++
} } })
我们设置在跟state中的属性会被vuex存储在根元素中
this._modules = new ModuleCollection(options)//初始化
const state = this._modules.root.state//获取定义的state
vuex初始化时先去获取定义在state属性中的值new ModuleCollection(options)进行模块收集(重新组装我们定义在store中的相关属性):
最终形成一棵module树
export default class ModuleCollection {
constructor (rawRootModule) {
// register root module (Vuex.Store options)
this.register([], rawRootModule, false)
}
get (path) {
return path.reduce((module, key) => {
return module.getChild(key)
}, this.root)
}
getNamespace (path) {
let module = this.root
return path.reduce((namespace, key) => {
module = module.getChild(key)
return namespace + (module.namespaced ? key + '/' : '')
}, '')
}
update (rawRootModule) {
update([], this.root, rawRootModule)
}
register (path, rawModule, runtime = true) {
if (process.env.NODE_ENV !== 'production') {
assertRawModule(path, rawModule)
}
const newModule = new Module(rawModule, runtime)
if (path.length === 0) {
this.root = newModule
} else {
const parent = this.get(path.slice(0, -1))
parent.addChild(path[path.length - 1], newModule)
} // register nested modules
if (rawModule.modules) {
forEachValue(rawModule.modules, (rawChildModule, key) => {
this.register(path.concat(key), rawChildModule, runtime)
})
}
}
unregister (path) {
const parent = this.get(path.slice(0, -1))
const key = path[path.length - 1]
if (!parent.getChild(key).runtime) return
parent.removeChild(key)
}
}
commit(=>mutations)时做了什么
const { dispatch, commit } = this
//初始化先绑定commit
this.commit = function boundCommit(type, payload, options) {
return commit.call(store, type, payload, options)
}
绑定之后注册mutation(commit的属性)
function registerMutation(store, type, handler, local) {
const entry = store._mutations[type] || (store._mutations[type] = [])
entry.push(function wrappedMutationHandler(payload) {
handler.call(store, local.state, payload)
})
}
commit(_type, _payload, _options) {
console.log('my name is zandianhui')
console.log(_type)
console.log(_payload)
console.log(_options)
// check object-style commit
const {
type,
payload,
options
} = unifyObjectStyle(_type, _payload, _options)
const mutation = {
type,
payload
}
//这是一个函数数组
const entry = this._mutations[type]
//判断当前设置的属性的值是否存在
if (!entry) {
if (process.env.NODE_ENV !== 'production') {
console.error(`[vuex] unknown mutation type: ${type}`)
}
return
}
//在执行mutation的时候,会将_committing设置为true,执行完毕后重置,在开启strict模式时,会监听state的变化,当变化时_committing不为true时会给出警告
this._withCommit(() => {
//迭代传入的commit数组
entry.forEach(function commitIterator(handler) {
handler(payload)
})
})
this._subscribers.forEach(sub => sub(mutation, this.state))
//当开发环境是抛出警告(如果commit的属性不存在)
if (
process.env.NODE_ENV !== 'production' &&
options && options.silent
) {
console.warn(
`[vuex] mutation type: ${type}. Silent option has been removed. ` +
'Use the filter functionality in the vue-devtools'
)
}
}
3.dispatch(=>actions)做了啥(初始化同commit)
//dispatch定义位置
this.dispatch = function boundDispatch(type, payload) {
return dispatch.call(store, type, payload)
}
绑定dispatch
function registerAction(store, type, handler, local) {
const entry = store._actions[type] || (store._actions[type] = [])
entry.push(function wrappedActionHandler(payload, cb) {
let res = handler.call(store, {
dispatch: local.dispatch,
commit: local.commit,
getters: local.getters,
state: local.state,
rootGetters: store.getters,
rootState: store.state
}, payload, cb)
//将res函数转为异步 promise
if (!isPromise(res)) {
res = Promise.resolve(res)
}
if (store._devtoolHook) {
return res.catch(err => {
store._devtoolHook.emit('vuex:error', err)
throw err
})
} else {
return res
}
})
}
注册actions dispatch(_type, _payload) {
// check object-style dispatch
const {
type,
payload
} = unifyObjectStyle(_type, _payload)
const action = {
type,
payload
}
const entry = this._actions[type]
if (!entry) {
if (process.env.NODE_ENV !== 'production') {
console.error(`[vuex] unknown action type: ${type}`)
}
return
}
try {
this._actionSubscribers
.filter(sub => sub.before)
.forEach(sub => sub.before(action, this.state))
} catch (e) {
if (process.env.NODE_ENV !== 'production') {
console.warn(`[vuex] error in before action subscribers: `)
console.error(e)
}
}
const result = entry.length > 1 ?
Promise.all(entry.map(handler => handler(payload))) :
entry[0](payload)
return result.then(res => {
try {
this._actionSubscribers
.filter(sub => sub.after)
.forEach(sub => sub.after(action, this.state))
} catch (e) {
if (process.env.NODE_ENV !== 'production') {
console.warn(`[vuex] error in after action subscribers: `)
console.error(e)
}
}
return res
})
}
还请大佬们勿喷,只是个人理解,还请多多指教!!