Vuex是什么?
Vuex是一个专为Vue.js应用开发的状态管理模式。集中式存储管理应用的所有组件的状态,并以相对的规则以可预判的方式发生变化。
这个状态管理应用包含以下几个部分:
- state 驱动应用的数据源;
- view 以声明方式将state映射到视图;
- actions 响应在view上的用户输入导致的状态变化。
Vuex和单纯的全局对象不同点:
1.Vuex的状态存储是响应式的,当Vue组件从store中读取状态时,若store中的state发生变化,那么相对于的组件也会相应地得到高校更新。
2.不能直接改变store中的状态,当我们需要去改变store中的状态时,我们的Vuex提供了两种方法,分别是commit和dispatch(异步),这样我们能够方便的跟踪每个状态的变化。
Vuex的基本用法如下:
import Vue from 'vue'
import Vuex from 'vuex'
// Vuex是一个对象 install方法
//Vuex中有一个Store类
//混入到组件中 增添store属性
Vue.use(Vuex)
const store = new Vuex.Store({
stgate:{
name:'chen'
},
mutations:{ //同步操作方法
changeName(state,name){ //method=> 同步的更改state mutation的参数是状态
state.name = name
}
},
actions:{ //异步操作方法
syncChangeName({commit},payload){
setTimeout(() => {
commit('changeName',payload)
)
}
},
getters:{ //计算属性
myName:state.name + '123'
}
})
现在我们开始整理vuex的原理实现,我们需要做的就是自己完成一个vuex的功能,Store的具体实现:
- 创建响应式的state,保存mutations,actions和getters
- 实现commit根据用户传入type执行相对应的mutataion
- 实现dispatch根据用户传入type执行对应的action,同时传递上下文
- 实现getters,按照getters定义对state做派生
实现Store类和state方法,代码如下:
let Vue;
class Vuex {
constructor(option = {}) {
// 将store中的state变成响应式
this._vm = new Vue({
data:{
$$state:options.state
}
})
}
get state() {
return this._vm._data.$$state
}
set state(v) {
//在直接改变state的时候给予警告,禁止直接修改state
console.error('please use replaceState to reset state')
}
functioninstall(_Vue){
Vue = _Vue;
//通过mixin的方法,在加载组件时,即挂载在Vue上
Vue.mixin({
beforeCreate() {
if(this.$option.store) {
//绑定在vue上作为全局对象
Vue.prototype.$store = this.$options.store
}
}
})
}
}
// 到处Store类和install方法
export default {Store, install}
实现修改state的commit方法:
class Store {
constructor(options = {}) {
//保存用户配置的mutations选项
this._mutataions = options.mutations || {}
}
commit(type, payload) {
const entry = this._mutations[type];
if(!entry) {
return console.error('unkonwn mutation type: $(type)');
return;
}
// 指定上下文为Store实例
// 传递state给mutataion
entry(this.state,payload)
}
}
VUex还提供了一种异步的修改state的dispatch方法:
class Store {
constructor(options = {}) {
//保存用户配置的actions选项
this._actions = options.actions || {}
//绑定commit上下文否则action中调用commit会出问题
//同时也把action绑了,因为action可以互调
const store = this;
const {commit, dispatch } = store;
this.commit = function boundCommit(type, payload) {
commit.call(store, type, payload)
}
this.action = function boundAction(type, payload) {
return action.call(store)
}
}
dispatch(type, payload) {
const entry = this._actions[type]
if(!entry) {
return console.error('unkonwn mutation type: $(type)');
return;
}
entry(this,payload)
}
}
getters的实现,代码如下:
class Store {
constructor(options = {}) {
this._state = options.state;
this._getters = options.getters;
this.getters = {};
this._vm = new Vue({
data: {
$$store: state
},
computed,
})
Object.key(_getters).forEach(key => {
Object.defineProperty(this.getters, key, {
//处理getters属性 具有缓存的 computed 带有缓存 (多次取值是如果值不变是不会重新取值)
get: () => options.getters[key](this.state)
})
})
forEachValue(options.getters, (fn, key)) => {
//将用户的getters 定义在实例上, 计算属性是如何实现缓存
computed[key] = () => fn(this.state);
//当取值的时候执行计算属性的逻辑,此时就有缓存功能
Object.defineProperty(this.getters, key, {
get: () => fn(this._vm[key])
})
}
}
}
computed具有缓存功能,可以在用户传入的getters的时候,将用户的getters 定义在实例上,computed[key] = () => fn(this.state) ,在取值的时候fn(this._vm[key])执行计算属性的逻辑。
vuex的相关辅助方法:
export function mapState(stateArr) {
let obj = {};
for (let i = 0; i < stateArr.length; i++) {
let stateName = stateArr[i];
obj[stateName] = function() {
return this.$store.state[stateName]
}
}
return obj
}
export function mapGetters(gettersArr) {
let obj = {};
for (let i = 0; i < gettersArr.length; i++) {
let gettName = gettersArr[i];
obj[gettName] = function() {
return this.$store.getters[gettName]
}
}
return obj
}
export function mapMutations(obj) {
let res = {};
Object.entries(obj).forEach(([key, value]) => {
res[key] = function (...args) {
this.$store.commit(value, ...args)
}
})
return res;
}
export function mapActions(obj) {
let res = {};
Object.entries(obj).forEach(([key, value]) => {
res[key] = function (...args) {
this.$store.dispatch(value, ...args)
}
})
return res;
}