一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第7天,点击查看活动详情。
一、什么是vuex
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
二、vuex的核心
每一个 Vuex 应用的核心就是 store(仓库)。store基本上就是一个容器,它包含着你的应用中大部分的状态 (state) 。Vuex 和单纯的全局对象有以下两点不同:
- Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
- 你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
三、vuex的核心概念
我们在面试中,我相信一定遇到过面试官问你,vuex有几个主要的部分,你讲一些这种问题。那么接下来我们看一下这几部分的概念。
1. State
Vuex 使用单一状态树,每个应用将仅仅包含一个 store 实例,存储在 Vuex 中的数据和 Vue 实例中的 data 遵循相同的规则。
Vuex 通过 store 选项,提供了一种机制将状态从根组件“注入”到每一个子组件中(需调用 Vue.use(Vuex))。
2. Getters
可以认为是store的计算属性,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
3. Mutations
我们在上面提到过想要修改store中的状态,只能通过提交 mutation的方式,并且它会接受 state 作为第一个参数。还有一个重要的规则是mutation 必须是同步函数。
4. Actions
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作。
Action 通过
store.dispatch方法触发。
5. Modules
当我们单一状态树对象很大时,store会很臃肿,Module就会允许我们将store进行分割,每个模块拥有自己的 state、mutation、action、getter。
然后我们看一个官网给的图,可以看出它大致的工作流程:
四、简单实现
我们会发现,我们在vue的项目中经常会引入一些其他的库,然后会有这样一行代码vue.use(×××),其实这样做是因为会调用插件的install方法,大家可以看看这里cn.vuejs.org/v2/guide/pl…
- 从我们使用Vuex的方式,是采用
new Vuex.Store,上面也说过vuex的核心就是一个store,所以我们知道vuex主要包括两部分,一个Store类,一个install方法。 - 在install方法里面我们知道,vue开发插件第一个参数是
Vue构造器,第二个参数是一个可选的选项对象,再使用Vue.mixin对钩子函数进行一个混入,注入组件选项。 - 在Store类中我们去实现那几个核心部分。
这里我们先不看Modules的实现的简单实现~
let Vue
class Store {
constructor (options = {}) {
this.vm = new Vue ({ // 我们的state是响应式的,我们就采用vue中的data来实现
data() {
return {
state: options.state
}
}
})
let getters = options.getters
this.getters = {}
// getters里面存放的是函数,但是我们直接调用拿到的是值,所以去循环执行下这个返回把结果返回
Object.keys(getters).forEach((getterKey) => {
Object.defineProperty(this.getters, getterKey, {
get: () => { // 这里需要注意this,我们采用箭头函数的方式
return getters[getterKey](this.state)
}
})
})
let mutations = options.mutations
this.mutations = {}
Object.keys(mutations).forEach((mutationKey) => {
Object.defineProperty(this.mutations, mutationKey, {
get: () => {
// mutations实现和getters差不多,这里需要注意,我们在mutations中声明的函数,第一个参数是state,第二个是payload
// 在commit中去执行的函数就是执行我们这里,payload就可以从commit方法中拿到了
return (payload) => mutations[mutationKey](this.state, payload)
}
})
})
let actions = options.actions
this.actions = {}
Object.keys(actions).forEach((actionsKey) => {
Object.defineProperty(this.actions, actionsKey, {
get: () => {
// 和mutations逻辑差不多
return (payload) => actions[actionsKey](this, payload)
}
})
})
}
get state() { // 这里是简化state的访问
return this.vm.state
}
commit = (mutationName, payload) => {
this.mutations[mutationName](payload)
}
dispatch = (actionsName, payload) => {
this.actions[actionsName](payload)
}
}
const install = (_Vue) => {
Vue = _Vue // 构造函数复制给全局变量Vue
// 在每个页面我们都可以拿到vuex,所以我们在生命周期里做一个混入
Vue.mixin({
beforeCreate () {
// console.log(this) // 这里的this是Vue的实例
if (this.$options && this.$options.store) { // 这里相当于我们在vue的根实例中引入的store
this.$store = this.$options.store
} else {
this.$store = this.$parent && this.$parent.$store // 在一般的组件中我们去找他父亲的store
}
}
})
}
export default {
Store,
install
}
到这里,初步简易的vuex就完成了~