github,blog
Vuex
Vuex
集中式 存储管理利用的所有组件的状态,并以相应的规定保障状态以 可预测 的形式发生变化。
装置 Vuex
vue add vuex
外围概念
- state:状态、数据
- mutations:更改状态的函数
- action:异步操作
- store:蕴含以上概念的容器
状态 – state
state
保留利用状态
export default new Vuex.Store({
state: {counter: 0}
})
<h1>
{{$store.state.counter}}
</h1>
状态变更 – mutations
mutations
用于批改状态
export default new Vuex.Store({
mutations:{add(state){state.counter++}
}
})
<h1 @click="$store.commit('add')">
{{$store.state.counter}}
</h1>
派生状态 – getters
从 state
派生进去新状态,相似计算属性
export default new Vuex.Store({
getters:{doubleCounter(state){return state.counter * 2;}
}
})
<h1>
{{$store.getters.doubleCounter}}
</h1>
动作 – actions
增加业务逻辑,相似于controller
export default new Vuex.Store({
actions:{add({commit}){setTimeout(() => commit('add'), 1000);
}
}
})
<h1 @tap="$store.dispatch('add')">
{{$store.state.counter}}
</h1>
Vuex 原理解析
任务分析
-
实现插件
-
实现 Store 类
- 维持一个响应式状态 state
- 实现 commit()
- 实现 dispatch()
- 实现 getters
- 挂载 $store
-
创立新的插件
在 Vue2.x
我的项目中的 src
门路下,复制一份 store
文件,重命名为ou-store
。
而后在 ou-store
门路下新建一个 ou-vuex.js
文件,并将 index.js
文件中的 Vuex
引入改为ou-vuex.js
。
import Vuex from './ou-vuex'
同时将 main.js
中的 router
引入也批改一下。
import router from './ou-vuex'
创立 vue 的插件
回头看一下 store/index.js
,首先是应用Vue.use()
注册了 Vuex
,而后再实例化了Vuex.Store
这个类,因而 Vuex
这个对象里含有一个 install
办法以及一个 Store
的类。
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({...})
因而咱们来创立一个新的 Vuex
插件。
let Vue; // 保留 Vue 的构造函数,插件中须要用到
class Store {}
function install(_Vue) {Vue = _Vue;}
export default {Store, install};
挂载$store
let Vue; // 保留 Vue 的构造函数,插件中须要用到
class Store {}
function install(_Vue) {
Vue = _Vue;
Vue.mixin({beforeCreate() {
// 挂载 $store
if(this.$options.store){Vue.prototype.$store = this.$options.store; // vm.$store}
}
})
}
export default {Store, install};
实现响应式保留 state
数据
因为 state
是一个对象,咱们能够应用 new Vue()
将state
转换为一个响应式数据进行保存起来。
其次,咱们不能显式去保留这个 state
,裸露给里面,因而咱们能够应用get
和set
去保留。
class Store {
/*
* options:
* state
* mutations
* actions
* modules
* getters
* */
constructor(options = {}) {
// data 响应式解决
this._vm = new Vue({
data: {$$state: options.state // 通过 this._vm._data.$$state 或 this._vm.$data.$$state 获取}
});
}
// 获取 state
get state() {return this._vm._data.$$state;}
// 不可设置 state
set state(v) {console.error('please use replaceState to reset state');
}
}
实现 commit
办法
当咱们应用 commit
办法时,都是 $store.commit(type,payload)
,第一个参数即mutations
的type
值,第二个是 payload
负载,而对应 mutation
办法的参数为 state
和payload
,因而咱们来实现:
class Store {constructor(options = {}) {
this._vm = new Vue({
data: {$$state: options.state}
});
// 保留用户配置的 mutations 选项
this._mutations = options.mutations;
}
get state() {return this._vm._data.$$state;}
set state(v) {console.error('please use replaceState to reset state');
}
commit(type, payload) {
// 获取 type 对应的 mutation
const entry = this._mutations[type]
if(!entry) {console.error(`unknown mutation type : ${type}`);
return ;
}
// 传递 state 和 payload 给 mutation
entry(this.state, payload)
}
}
实现 dispatch
办法
dispatch
办法跟 commit
办法大同小异,不同之处在于 dispatch
调用的是 action
异步函数,而 action
的参数为 context
和payload
,payload
咱们能够通过 dispatch
的参数获取到,而 context
执行上下文其实就是实例中的this
。
但 action
是用来解决异步函数的,因而咱们须要对 dispatch
办法进行 this
绑定;同时,action
办法中有可能会调用到 commit
办法,因而咱们也须要对 commit
办法进行 this
绑定。
class Store {constructor(options = {}) {
this._vm = new Vue({
data: {$$state: options.state}
});
// 保留用户配置的 mutations 选项和 actions 选项
this._mutations = options.mutations;
this._actions = options.actions;
// 将 commit 和 dispatch 绑定 this,this.commit = this.commit.bind(this);
this.dispatch = this.dispatch.bind(this);
}
get state() {return this._vm._data.$$state;}
set state(v) {console.error('please use replaceState to reset state');
}
commit(type, payload) {const entry = this._mutations[type]
if(!entry) {console.error(`unknown mutation type : ${type}`);
return ;
}
entry(this.state, payload)
}
dispatch(type, payload) {
// 获取用户编写的 type 对应的 action
const entry = this._actions[type];
if(!entry) {console.error(`unknown action type : ${type}`)
}
// 异步后果解决经常须要返回 Promise
return entry(this, payload)
}
}
实现 getters
派生状态
当咱们定义 getters
状态时,实际上是定义了一个function
。
getters: {doubleCounter(state) {return state.counter * 2;}
},
而应用 getters
中某一个派生状态时,实际上是失去一个值,也就是这个 function
的返回值。
<h4>double count: {{$store.getters.doubleCounter}}</h4>
这其实就有点像对象中的 get
属性,因而咱们能够应用 Object.defineProperty()
来实现getters
。
class Store {constructor(options = {}) {
this._vm = new Vue({
data: {$$state: options.state}
});
this._mutations = options.mutations;
this._actions = options.actions;
this.commit = this.commit.bind(this);
this.dispatch = this.dispatch.bind(this);
// 初始化 getters,默认为一个空对象
this.getters = {};
// 遍历 options.getters
for (const key in options.getters) {
const self = this;
Object.defineProperty(
this.getters,
key, // key 名
{get() {
// 调用对应的函数,第一个参数为 state,将后果返回
return options.getters[key](self._vm._data.$$state)
}
}
)
}
}
}