Vuex
Vuex 集中式
存储管理应⽤的所有组件的状态,并以相应的规则保证状态以可预测
的⽅式发⽣变化。
下面是Vuex工作的流程图
安装: vue add vuex
vue add vuex
核⼼概念
- State 状态,数据
- Actions 异步操作
- Mutations 更改状态的函数
- store 包含以上概念的容器
状态 -state
state用来存储状态
export default new Vuex.Store({
state: {
count: 0
},
})
状态变更 - mutations
mutations⽤于修改状态,store.js
mutations: {
add(state) {
state.count++
}
}
派⽣状态 - getters
从state派⽣出新状态,类似计算属性
export default new Vuex.Store({
getters: {
doubleCounter(state) { // 计算剩余数量
return state.count * 2;
}
}
})
动作 - actions
添加业务逻辑,类似于controller(副作用操作)
export default new Vuex.Store({
actions: {
add({ commit }) {
setTimeout(() => {
commit('add')
}, 1000);
}
}
})
测试的代码
<p @click="$store.commit('add')">conunt: {{$store.state.count}}</p>
<p @click="$store.dispatch('add')">async conunt: {{$store.state.count}}</p>
vuex原理解析
分析
- 实现⼀个插件:声明Store类,挂载$store
- Store具体实现:
- 创建响应式的state,保存mutations、actions和getters
- 实现commit根据⽤户传⼊type执⾏对应mutation
- 实现dispatch根据⽤户传⼊type执⾏对应action,同时传递上下⽂
- 实现getters,按照getters定义对state做派⽣
- 挂载$store
初始化:Store声明、install实现,kvuex.js
创建一个kvue.js文件
// 实现一个插件
let _Vue
class Store {
constructor(options) {
// 需要保存一下 mutations以及actions
this._mutations = options.mutations
this._actions = options.actions
// 创建响应式的state
this._vm = new _Vue({
// 借助vue 的响应式
data () {
// data 这个对象中个key最终都会被代理到vue这个实例中去
return {
// 不希望被代理,就加上$
$$state: options.state
}
}
})
}
// 暴露给外界的方法,让用户可以访问
get state () {
return this._vm._data.$$state
}
set state (v) {
// 不允许对state直接做替换, 所有的操作都是可控的
console.error('please use replaceState to reset state')
}
}
function install(Vue) {
_Vue = Vue
// 混入
Vue.mixin({
beforeCreate() {
// 判断是否有store选项
if (this.$options.store) {
Vue.prototype.$store = this.$options.store
}
}
})
}
// 导出的对象就是Vuex
export default { Store, install }
为什么要⽤混⼊⽅式写?主要原因是use代码在前,Router实例创建在后,⽽install逻辑⼜需要⽤ 到该实例,这里是一个比较巧妙的方法(主要是为了延迟执行)
实现commit:根据⽤户传⼊type获取并执⾏对应mutation
class Store {
constructor(options = {}) {
// 保存⽤户配置的mutations选项
this._mutations = options.mutations || {}
}
commit(type, payload) {
// 获取type对应的mutation
const entry = this._mutations[type]
if (!entry) {
console.error(`unknown mutation type: ${type}`);
return
}
// 指定上下⽂为Store实例
// 传递state给mutation
entry(this.state, payload);
}
}
实现actions:根据⽤户传⼊type获取并执⾏对应action
class Store {
constructor(options = {}) {
// 保存⽤户编写的actions选项
this._actions = options.actions || {}
// 绑定commit上下⽂否则action中调⽤commit时可能出问题!!
// 同时也把action绑了,因为action可以互调
const store = this
const {commit, action} = store
this.commit = function boundCommit(type, payload) {
commit.call(store, type, payload)
}
this.action = function boundAction(type, payload) {
return action.call(store, type, payload)
}
}
dispatch(type, payload) {
// 获取⽤户编写的type对应的action
const entry = this._actions[type]
if (!entry) {
console.error(`unknown action type: ${type}`);
return
}
// 异步结果处理常常需要返回Promise
return entry(this, payload);
}
}
下面附上完整代码
// 实现一个插件
let _Vue
class Store {
constructor(options = {}) {
// 需要保存一下 mutations以及actions
this._mutations = options.mutations
this._actions = options.actions
// 创建响应式的state
this._vm = new _Vue({
// 借助vue 的响应式
data () {
// data 这个对象中个key最终都会被代理到vue这个实例中去
return {
// 不希望被代理,就加上$
$$state: options.state
}
}
})
// 修改this 的指向
this.commit = this.commit.bind(this)
this.dispatch = this.dispatch.bind(this)
}
// 暴露给外界的方法,让用户可以访问
get state () {
return this._vm._data.$$state
}
set state (v) {
// 不允许对state直接做替换, 所有的操作都是可控的
console.error('please use replaceState to reset state')
}
// 实现commit方法
// 修改state
// this.$store.commit('add', 1)
commit (type, payload) {
// 获取type对应的mutation
const entry = this._mutations[type]
if (!entry) {
// 如果不存在就做一次警告
console.error('unknown mutation')
return
}
// 传入state作为参数,
entry(this.state, payload)
}
// 实现dispatch方法
dispatch (type, payload) {
// 获取type对应的actions
const entry = this._actions[type]
if (!entry) {
// 如果不存在就做一次警告
console.error('unknown action')
return
}
// 传入Stores实例做参数(上下文),
return entry(this, payload)
}
}
function install(Vue) {
_Vue = Vue
// 混入
Vue.mixin({
beforeCreate() {
// 判断是否有store选项
if (this.$options.store) {
Vue.prototype.$store = this.$options.store
}
}
})
}
// 导出的对象就是Vuex
export default { Store, install }