Vuex
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
简单地说:对vue应用中多个组件的共享状态进行集中式的管理(读/写)
安装
npm install vuex
yarn add vuex
在一个模块化的打包系统中,必须显式地通过 Vue.use()
来安装 Vuex:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
store(仓库)
Vuex
应用的核心是就是store,“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。Vuex
和单纯的全局对象有以下两点不同:
1.Vuex 的状态存储是响应式的。当Vue
组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
2.你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
创建
// store对象中包含读取数据和更新数据的方法
const store = new Vuex.Store({
state,
actions,
mutations,
});
// 暴露出去
export default store;
为了在 Vue
组件中访问 this.$store
property,需要为 Vue
实例提供创建好的 store。
import store from "./store";
new Vue({
render: (h) => h(App),
// 应用store
store,
}).$mount("#app");
State
单一状态树
Vuex
使用单一状态树,用一个对象就包含了全部的应用层级状态。作为一个“唯一数据源 ”而存在.
这也意味着,每个应用将仅仅包含一个 store 实例。
const state = {
// 数据的初始化
count: 0,
};
Mutation
更改 Vuex
的 store 中的状态的唯一方法是提交 mutation。每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数.在 Vuex
中,也可以向 store.commit
传入额外的参数,即 mutation 的 载荷(payload):
const mutations = {
// mutation函数第一个参数:state --> 所有状态数据
// mutation函数第二个参数:num --> 就由上一步actions负责传递过来
INCREMENT(state, num) {
state.count += num;
},
DECREMENT(state, num) {
state.count -= num;
},
};
Mutation 需遵守 Vue
的响应规则
既然Vuex
的 store 中的状态是响应式的,那么当我们变更状态时,监视状态的 Vue
组件也会自动更新。这也意味着 Vuex
中的 mutation 也需要与使用Vue
一样遵守一些注意事项:
- 最好提前在你的 store 中初始化好所有所需属性。
- 当需要在对象上添加新属性时,你应该
- 使用
Vue.set(obj, 'newProp', 123)
, 或者 - 以新对象替换老对象。例如,利用[对象展开运算符 我们可以这样写:
state.obj = { ...state.obj, newProp: 123 }
Actions
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作。
注册一个action:
const actions = {
// actions函数第一个参数是一个对象:store --> 内部有dispatch/commit/state等
// actions函数第二个参数:组件中分发dispatch传递过来的数据
increment(store, num) {
console.log(store, num);
// 触发某一个mutation函数
// store.commit(触发的mutation函数名称, mutation函数要接受的数据);
store.commit("INCREMENT", num);
},
incrementAsync({ commit }, num) {
setTimeout(() => {
commit("INCREMENT", num);
}, 1000)
},
isType({ commit, state: { count } }) {
if (count % 2 === 1) {
commit("ISTYPEODD");
return
}
commit("ISTYPEEVEN")
}
};
分发Action
组件中Action 通过 this.$store.dispatch
方法触发:
methods: {
increment() {
// 更新vuex数据 --> dispatch 调用store中的actions 并传递数据
this.$store.dispatch("increment", this.num);
this.$store.dispatch("isType");
},
decrement() {
this.$store.dispatch("decrement", this.num);
this.$store.dispatch("isType");
},
incrementAsync() {
this.$store.dispatch("incrementAsync", this.num);
setTimeout(() => { // 可以异步调用
this.$store.dispatch("isType");
}, 1000);
},
}
Actions 支持同样的载荷方式和对象方式进行分发:
// 以载荷形式分发
store.dispatch('incrementAsync', {
amount: 10
})
// 以对象形式分发
store.dispatch({
type: 'incrementAsync',
amount: 10
})
getters
Vuex
可以在store中定义getters(可以认为是 store 的计算属性).
Getter 接受 state 作为其第一个参数:
const getters = {
oddOrEven(state) {
// Math.abs() 取绝对值(正数)
return Math.abs(state.count) % 2 === 1 ? "奇数" : "偶数";
}
}
Getter 会暴露为 store.getters
对象,可以以属性的形式访问这些值:
store.getters.xxx
辅助函数
/*
mapState 映射vuex状态数据到组件data数据中 计算属性computed中
mapGetters 映射vuex的store中的 getters数据到组件computed数据中
mapActions 映射vuex actions函数到组件methods中
mapMutations 映射vuex mutations函数到组件methods中
*/
导入
import { mapState, mapGetters, mapActions, mapMutations } from "vuex";
computed: {
/*
mapState(["count"]) 的返回值是一个对象
{
count(){
return this.$store.state.count
}
}
*/
...mapState(["count"]),
...mapGetters(["oddOrEven"])
},
methods: {
...mapActions(["incrementIfOdd", "incrementAsync"]),
...mapMutations([INCREMENT, DECREMENT]),
increment() {
//this.$store.commit("INCREMENT", this.num);
// 调用的就是mutation函数
this.INCREMENT(this.num);
},
incrementIfOdd() {
//this.$store.dispatch("incrementIfOdd", this.num);
this.INCREMENT(this.num)
},
}
vuex 工作流程
-
读取
- 组件直接调用 this.$store.state.xxx
- mapState([‘count’])
- 组件直接调用 this.$store.getters.xxx
- mapGetters([‘oddOrEven’])
- 组件直接调用 this.$store.state.xxx
-
更新
-
组件调用 this.$store.dispatch(‘action 函数名称’, 数据)
- mapActions([‘increment’])
-
触发某个 actions 函数,actions 函数中发送请求,请求成功调用 commit(‘mutation 函数名称’, 数据)
-
触发某个 mutations 函数,mutations 函数就会对 state 数据进行直接修改
-
数据一旦更新,因为响应式的原因,所以用户界面也会发生变化
-
组件调用 this.$store.commit(‘mutation 函数名称’, 数据)
- mapMutations([‘INCREMENT’])
-
触发某个 mutations 函数,mutations 函数就会对 state 数据进行直接修改
-
数据一旦更新,因为响应式的原因,所以用户界面也会发生变化
-
思考:
- 状态数据要不要定义在 vuex 中?
- 看数据是否有多个组件要使用(显示、操作)
- 要对 vuex 的数据进行操作,要不要 actions?
- 要数据需不需要进一步处理(操作:发送请求…)
- mutation 函数要定义多少个?
- 看要对数据进行几种类型的操作