# Hello Vuex
Vuex 是专为 Vue.js 开发的状态管理模式,采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态可预测的方式发生变化
- 安装
vue add vuex
# 基础使用
State
- 将应用全局状态定义在
state
中
// store/index.js
export default new Vuex.Store({
state: {
isLogin: false,
}
});
Mutation
- 修改
state
只能通过mutation
export default new Vuex.Store({
// ...
mutations: {
login(state) {
state.isLogin = true;
},
logout(state) {
state.isLogin = false;
},
}
});
获取和修改状态
- 使用
$store.state
获取属性
<button @click="login" v-if="!$store.state.isLogin">Login</button>
<button @click="logout" v-else>Logout</button>
- 修改状态只能通过
store.dispatch(mutation)
this.$store.commit('login');
this.$store.commit('logout');
Action
- Action 类似于 mutation
- 但是,Action 提交的是 mutation,而不是直接变更状态
- Action 可以包含任意异步操作
// store/index.js
actions: {
// 参数1 是vuex传递的上下文context
login({ commit }, username) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (username === 'admin') {
commit('login');
resolve();
} else {
reject();
}
}, 1000);
});
},
}
- 派发动作
this.$store.dispatch('login', 'admin').then(() => {
// 业务逻辑
})
# 模块化
使用 modules
定义多个子模块利于组件复杂状态
import user from './user'
export default new Vuex.Store({
modules: {
user,
}
})
在子模块中维护状态
代码语言:javascript复制export default {
namespaced: true, // 避免命名冲突
// 状态及维护逻辑
}
访问方式加上命名空间
代码语言:javascript复制this.$store.dispatch('user/login', 'admin').then(() => {})
this.$store.commit('user/logout');
// store.state.user.isLogin
# mapState()/mapMutation()/mapAction()
通过这些方法,可以简化访问方式
代码语言:javascript复制import { mapState } from 'vuex';
export default {
// 展开后可直接访问 isLogin
computed: {
...mapState('user', ['isLogin']),
}
}
维护
代码语言:javascript复制import { mapActions } from 'vuex';
export default {
methods: {
login() {
this.['user/login']('admin').then(() => {})
},
...mapActions(['user/login', 'user/logout']),
}
}
# Getter
可以用 getters
从 store
的 state
中派生出一些状态,类似于计算属性
export default {
namespaced: true, // 设置独立命名空间,避免命名冲突
state: {
isLogin: false,
username: '',
},
getters: {
welcome: (state) => `${state.username},欢迎回来`,
},
}
# 严格模式
严格模式下,强制要求状态变更必须由 mutation
维护
export default new Vuex.Store({
strict: true,
})
# 插件
Vuex 的 store
接受 plugins
选项,这个选项暴露出每次 mutation
的钩子。Vuex 插件就是一个函数,它接收 store
作为唯一参数
const myPlugin = (store) => {
// 当 store 初始化后调用
};
插件注册
代码语言:javascript复制const store = new Vuex.Store({
// ...
plugins: [myPlugin],
});
# 简易实现
Vuex 集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以可预测的方式发生变化。
# 需求分析
- 实现一个插件:声明
Store
类,挂载$store
Store
具体实现- 创建响应式的
state
,保存mutations
,actions
和getters
- 实现
commit
根据用户传入type
执行对应mutation
- 实现
dispatch
根据用户传入type
执行对应action
,同时传递上下文 - 实现
getters
,按照getters
定义对state
做派生
- 创建响应式的
# 实现
- 实现一个插件
// cvuex.js
let Vue;
class Store {
constructor(options) {
// 响应化处理state
this.state = new Vue({
data: options.state,
})
}
}
function install(_Vue) {
Vue = _Vue;
Vue.mixin({
beforeCreate() {
if (this.$options.store) {
Vue.prototype.$store = this.$options.store;
}
}
})
}
// cvuex
export default {
Store,
install,
}
- 实现commit
// cvuex.js
class Store {
constructor(options) {
this._mutations = options.mutations;
// 响应化处理state
this.state = new Vue({
data: options.state,
})
}
// store.commit('add', 1)
/**
* @type mutation的类型
* @payload 参数
*/
commit(type, payload) {
const entry = this._mutations[type];
if (entry) {
entry(this.state, payload);
}
}
}
- 实现dispatch
// cvuex.js
class Store {
constructor(options) {
this._mutations = options.mutations;
this._actions = options.actions;
// 响应化处理state
this.state = new Vue({
data: options.state,
})
// 绑定commit、dispatch的上下文为store实例
this.commit = this.commit.bind(this);
this.dispatch = this.dispatch.bind(this);
}
commit(type, payload) {
const entry = this._mutations[type];
if (entry) {
entry(this.state, payload);
}
}
dispatch(type, payload) {
const entry = this._actions[type];
if (entry) {
entry(this, payload);
}
}
}
- 实现getters
class Store {
constructor(options) {
// ...
this._wrappedGetters = options.getters;
const computed = {};
this.getters = {};
const store = this;
Object.keys(this._wrappedGetters).forEach(key => {
// 获取用户定义的getter
const fn = store._wrappedGetters[key];
// 转换为computed可以使用的无参数形式
computed[key] = function() {
return fn(store.state);
}
// 为getters定义只读属性
Object.defineProperty(store.getters, key, {
get: () => store._vm[key]
});
})
this._vm = new Vue({
data: {
// 加两个$$ vue创建的时候不会做代理,对外隐藏
$$state: options.state,
},
computed
});
}
// ...
}