- 思考:为什么Vue Components不与Mutations直接相连
- 原因: Mutations每个方法完成的事件要尽可能单一,devtools无法监听mutations方法内的多个操作,但是actions可以提交多次给Mutations,所以进行多个操作时,先在actions里进行多个操作,在Actions里将多个操作拆分成一个一个操作发送给mutations
1.Vuex的基本使用
- 介绍:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。
- 意义:比如一个项目中要共享某一个状态,用户id,用户头像等,这些信息可以统一管理起来,做全局变量
- 基本使用步骤
- 第一步:和vue-router一样先创建一个index.js并且调用 Vue.use(Vuex)
- 第二步:创建Vuex实例并传入state/mutations等参数(state传参数,mutation传调用函数)
- 第三步:在Vue实例(main.js中)中挂载创建的Vuex实例
- 第四步:在组件中使用调用函数
- 第五步:前往devtools查看状态的改变
- 代码:
index.js:
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
counter: 6666
},
mutations: {
inc(state){
state.counter++;
},
dec(state){
state.counter--;
}
}
});
export default store;
App.vue:
<template>
<div id="app">
<h2>counter:{
{
$store.state.counter}}</h2>
<button @click="add">+</button>
<button @click="sub">-</button>
</div>
</template>
<script>
export default {
name: 'App',
methods: {
add(){
this.$store.commit("inc");
},
sub(){
this.$store.commit("dec");
}
}
}
</script>
- 效果:
可以正常+/-,devtools也正常检查
2.State单一状态树
引用王红元老师的一段话:
- 我们知道,在国内我们有很多的信息需要被记录,比如上学时的个人档案,工作后的社保记录,公积金记录,结婚后的婚姻信息,以及其他相关的户口、医疗、文凭、房产记录等等(还有很多信息)。这些信息被分散在很多地方进行管理,有一天你需要办某个业务时(比如入户某个城市),你会发现你需要到各个对应的工作地点去打印、盖章各种资料信息,最后到一个地方提交证明你的信息无误。
- 如果你的状态信息是保存到多个Store对象中的,那么之后的管理和维护等等都会变得特别困难。所以Vuex也使用了单一状态树来管理应用层级的全部状态。单一状态树能够让我们最直接的方式找到某个状态的片段,而且在之后的维护和调试过程中,也可以非常方便的管理和维护。
3.Vuex-getters的使用
- 介绍:getters和state的关系类似于 data和computed ,更复杂的属性
- 案例:state中有一个学生数组,要显示其中年龄大于20的学生,还要显示其中大于自己定义年龄的学生
- 代码:
index.js:
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
student:[
{
id: 110, name: 'jjj', age: 18},
{
id: 111, name: 'ffffe', age: 24},
{
id: 112, name: 'sss', age: 30},
{
id: 113, name: 'rrry', age: 10}
]
},
getters: {
more20stu(state){
return state.student.filter(student => student.age > 20);
},
moreAgeStu(state){
return age => {
return state.student.filter(student => student.age > age);
}
}
}
});
export default store;
App.vue:
<template>
<div id="app">
<h2>student:{
{
$store.getters.more20stu}}</h2>
<h2>student:{
{
$store.getters.moreAgeStu(8)}}</h2>
</div>
</template>
<script>
export default {
name: 'App',
}
</script>
- 结果 :
- 总结:当属性需要运算再显示的时候就使用getters
4.mutations
- 介绍:Vuex的store状态的更新唯一方式:提交Mutation
- 用法:mutations传递可以参数,还有两种提交风格
- 普通方式提交代码:
App.vue
<button @click="addCount(5)">+5</button>
<button @click="addStudent()">加入学生</button>
addCount(count){
this.$store.commit({
type: "addCount",
count
})
},
addStudent(){
let student = {
id: 114, name: "114fff", age: 18};
this.$store.commit("addStudent", student);
}
- 第二种风格方式提交代码:
App.vue
<button @click="addCount(5)">+5</button>
addCount(count){
//method2
this.$store.commit({
type: "addCount",
count
})
}
index.js:
mutations: {
addCount(state, payload){
console.log(payload);
state.counter += payload.count;
}
},
- 打印结果:
5.Mutation响应规则
Vuex的store中的state是响应式的, 当state中的数据发生改变时, Vue组件会自动更新,若要达到响应式效果,提前在store中初始化好所需的属性,没有初始化的属性要达到响应式,需要采取特殊方法
- 未初始化的属性要达到响应式的写法:
- 代码:
index.js:
const store = new Vuex.Store({
state: {
info: {
id: 8888,
name: "Helen",
age: 99
}
},
mutations: {
updateInfo(state){
//method1 :非响应式
state.info["extra"] = "extraInfo";
//method2: 响应式
Vue.set(state.info, 'extra', "extraInfo")
}
}
});
- 非响应式结果:
- 响应式结果:
6.actions
- 介绍:Action类似于Mutation, 但是是用来代替Mutation进行异步操作的
- 意义:Mutation中可以进行异步操作,但是devtools中无法监听异步操作,想要devtools监听异步操作,先经过actions再commit给mutations
- context:context是和store对象具有相同方法和属性的对象
- 代码样例:
App.vue
updateInfo(){
this.$store.dispatch({
type: "aUpdateInfo",
message: "我是payload里面一个默默无闻的message",
success: () => {
//设置一个回调函数,执行完commit就调用
console.log("我是一个App.vue里的回调函数success");
}
})
}
index.js:
const store = new Vuex.Store({
state: {
info: {
id: 8888,
name: "Helen",
age: 99
}
},
mutations: {
updateInfo(state){
state.info.age = 18;
}
},
actions: {
aUpdateInfo(context, payload) {
setTimeout(() => {
context.commit("updateInfo");
console.log(payload.message);
payload.success(); //设置一个回调函数,执行完commit就调用
}, 1000)
}
}
});
- 结果:
- 更优秀的回调方法(Promise)
index.js:
actions: {
aUpdateInfo(context, payload) {
return new Promise((resolve) => {
setTimeout(() => {
context.commit("updateInfo");
resolve("我是resolve里的内容");
}, 1000)
});
}
}
App.vue:
updateInfo(){
this.$store
.dispatch({
type: "aUpdateInfo",
}) //this.$store.dispatch相当于aUpdateInfo函数中return的promise
.then(res => {
console.log(res);
})
}
7.modules
- 介绍: Vue使用单一状态树,那么也意味着很多状态都会交给Vuex来管理,Vuex允许我们将store分割成模块(Module), 而每个模块拥有自己的state、mutations、actions、getters,这样来避免store臃肿
- 用法:除了调用state外,其余用法和store主体一样,getters,mutations,actions所调用的state,context不会调用到store主体,只会在自身模块里调用,想要调用主体用rootState,rootGetters
- 案例:
index.js
const moduleA = {
state: {
messageA: "我是moduleA中的message"
},
mutations: {
updateMessageA(state, payload){
state.messageA = "6666666666666666"+ payload;
}
},
getters: {
aGetTest(state){
return state.messageA + "aGetTest";
},
aGetTest2(state, getters){
return getters.aGetTest + "222222222";
}
},
actions: {
asyncUpdateMessageA(context){
setTimeout(() => {
context.commit("updateMessageA", "我是异步操作的payload")
}, 1000)
}
}
};
const store = new Vuex.Store({
modules: {
a: moduleA
}
});
App.vue:
<p>-------------------探究modules---------------------</p>
<h2>messageA:{
{
$store.state.a.messageA}}</h2>
<h2>getter测试:{
{
$store.getters.aGetTest}}</h2>
<h2>getter2测试:{
{
$store.getters.aGetTest2}}</h2>
<button @click="updateMessageA">测试moduleA-mutations</button>
<button @click="asyncUpdateMessageA">测试moduleA-actions</button>
updateMessageA(){
this.$store.commit("updateMessageA", "我是payload");
},
asyncUpdateMessageA(){
this.$store.dispatch("asyncUpdateMessageA");
}
- 同步操作效果展示:
- 异步操作效果展示: