129. Vuex:概念和作用解析
Vuex是做什么的?
- 官方解释:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。
- 它采用***集中式存储管理***应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
- Vuex也集成到 Vue 的官方调试工具devtools extension,提供了诸如零配置的time-travel调试、状态快照导入导出等高级调试功能。
管理什么状态呢?
130. Vuex:单界面到多界面状态管理切换
单界面的状态管理
State:不用多说,就是我们的状态。(姑且可以当做就是data中的属性)
View:视图层,可以针对State的变化,显示不同的信息。
Actions:这里的Actions主要是用户的各种操作:点击、输入等等,会导致状态的改变。
单界面状态管理的实现
多界面状态管理
- 全局单例模式(大管家)
- 我们现在要做的就是将共享的状态抽取出来,交给我们的大管家,统一进行管理。
- 之后,你们每个试图,按照我规定好的规定,进行访问和修改等操作。
- 这就是Vuex背后的基本思想。
Vuex状态管理图例
131. Vuex:devtools和mutations
简单的案例
chrome网上应用商店搜索:vue.js devtools
实现一下之前简单的案例:
存放Vuex代码:创建一个文件夹store,并且在其中创建一个index.js文件,在index.js文件中写入如下代码。
挂载到Vue实例中
- 其次,让所有的Vue组件都可以使用这个store对象
- 来到main.js文件,导入store对象,并且放在new Vue中
- 这样,在其他Vue组件中,我们就可以通过this.$store的方式,获取到这个store对象了
使用Vuex的count
- 这就是使用Vuex最简单的方式了。
- 来对使用步骤,做一个简单的小结:
- 提取出一个公共的store对象,用于保存在多个组件中共享的状态
- 将store对象放置在new Vue对象中,这样可以保证在所有的组件中都可以使用到
- 在其他组件中使用store对象中保存的状态即可
- 通过this.$store.state.属性的方式来访问状态
- 通过this.$store.commit(‘mutation中方法’)来修改状态
- 注意事项:
- 我们通过提交mutation的方式,而非直接改变store.state.count。
- 这是因为Vuex可以更明确的追踪状态的变化,所以不要直接改变store.state.count的值。
132. Vuex:state单一状态树的理解
Vuex核心概念
- State
- Getters
- Mutation
- Action
- Module
State单一状态树
133. Vuex:getters使用详解
Getters基本使用
有时候,我们需要从store中获取一些state变异后的状态,比如下面的Store中:
- 获取学生年龄大于20的个数
我们可以在Store中定义getters
Getters作为参数和传递参数
如果我们已经有了一个获取所有年龄大于20岁学生列表的getters, 那么代码可以这样来写
getters默认是不能传递参数的, 如果希望传递参数, 那么只能让getters本身返回另一个函数
- 比如上面的案例中,我们希望根据ID获取用户的信息
代码:
store/index.js:
import Vue from 'vue'
import Vuex from 'vuex'
import mutations from './mutations'
import actions from './actions'
import getters from './getters'
import moduleA from './modules/moduleA'
// 1.安装插件
Vue.use(Vuex)
// 2.创建对象
const store = new Vuex.Store({
state: {
counter: 1000,
students: [
{ id: 110, name: 'why', age: 18 },
{ id: 111, name: 'kobe', age: 24 },
{ id: 112, name: 'james', age: 30 },
{ id: 113, name: 'curry', age: 10 }
],
},
mutations: {
// 方法
increment(state) {
state.counter++;
},
decrement(state) {
state.counter--;
}
},
actions,
getters: {
powerCounter(state) {
return state.counter * state.counter
},
more20stu(state) {
return state.students.filter(s => s.age > 20)
},
more20stuLength(state, getters) {
return getters.more20stu.length
},
moreAgeStu(state) {
return function (age) {
return state.students.filter(s => s.age > age)
}
// 不推荐下面写法,阅读性太差
/* return age => {
return state.students.filter(s => s.age > age)
} */
}
},
modules: {
a: moduleA
}
})
// 3.导出store独享
export default store
// 对象的解构
const obj = {
name: 'why',
age: 18,
height: 1.88,
address: '洛杉矶'
}
const { name, height, age } = obj;
App.vue:
<template>
<div id="app">
<h2>------APP中的内容------</h2>
<h2>{{ message }}</h2>
<h2>{{ $store.state.counter }}</h2>
<button @click="addition">+</button>
<button @click="subtraction">-</button>
<h2>------APP中的内容:getters相关信息------</h2>
<h2>{{ $store.getters.powerCounter }}</h2>
<h2>{{ $store.getters.more20stu }}</h2>
<h2>{{ $store.getters.more20stuLength }}</h2>
<h2>{{ $store.getters.moreAgeStu(12) }}</h2>
<h2>------Hello Vuex中的内容------</h2>
<hello-vuex />
</div>
</template>
<script>
import HelloVuex from "./components/HelloVuex";
export default {
name: "App",
components: {
HelloVuex,
},
data() {
return {
message: "我是APP组件",
};
},
computed: {
/* more20stu() {
return this.$store.state.students.filter(s => s.age > 20)
} */
},
methods: {
addition() {
this.$store.commit("increment");
},
subtraction() {
this.$store.commit("decrement");
},
},
}
</script>
<style>
</style>
HelloVuex.vue:
<template>
<div>
<h2>我是vuex组件</h2>
<h2>{{ $store.state.counter }}</h2>
<h2>{{ $store.getters.powerCounter }}</h2>
<h2>{{ $store.getters.more20stu }}</h2>
</div>
</template>
<script>
export default {
name: "HelloVuex",
};
</script>
<style>
</style>
结果:
134. Vuex:mutations的携带参数
Mutation状态更新
Vuex的store状态的更新唯一方式:提交Mutation
- Mutation主要包括两部分:
- 字符串的事件类型(type)*
- 一个回调函数(handler),该回调函数的第一个参数就是state。
mutation的定义方式:
通过mutation更新:
Mutation传递参数
Vuex的store状态的更新唯一方式:提交Mutation
- Mutation主要包括两部分:
- 字符串的事件类型(type)
- 一个回调函数(handler),该回调函数的第一个参数就是state
mutation的定义方式:
通过mutation更新:
Mutation传递参数
-
在通过mutation更新数据的时候, 有可能我们希望携带一些额外的参数
- 参数被称为是mutation的载荷(Payload)
Mutation中的代码:
- 参数被称为是mutation的载荷(Payload)
-
但是如果参数不是一个呢?
- 比如我们有很多参数需要传递.
- 这个时候, 我们通常会以对象的形式传递, 也就是payload是一个对象
- 这个时候可以再从对象中取出相关的信息
135. Vuex:mutations的提交风格
上面的通过commit进行提交是一种普通的方式
Vue还提供了另外一种风格, 它是一个包含type属性的对象:
Mutation中的处理方式是将整个commit的对象作为payload使用, 所以代码没有改变, 依然如下:
136. Vuex:数据的响应式原理
Mutation响应规则
Vuex的store中的state是响应式的, 当state中的数据发生改变时, Vue组件会自动更新
- Vuex对应的规则:
- 提前在store中初始化好所需的属性.
- 当给state中的对象添加新属性时, 使用下面的方式:
- 方式一: 使用Vue.set(obj, ‘newProp’, 123)
- 方式二: 用心对象给旧对象重新赋值
一个例子:
当我们点击更新信息时, 界面并没有发生对应改变。
让它改变的方法:
下面代码的方式一和方式二,都可以让state中的属性是响应式的
137. Vuex:mutations的类型常量
Mutation常量类型 – 概念
项目过大时,可以使用常量替代Mutation事件的类型
创建一个文件: mutation-types.js, 并且在其中定义我们的常量.
定义常量时, 我们可以使用ES2015中的风格, 使用一个常量来作为函数的名称
138. Vuex:actions的使用详解
Mutation同步函数
- 通常情况下, Vuex要求我们Mutation中的方法必须是同步方法.
- 主要的原因是当我们使用devtools时, 可以devtools可以帮助我们捕捉mutation的快照.
- 但是如果是异步操作, 那么devtools将不能很好的追踪这个操作什么时候会被完成
因此,通常情况下, 不要再mutation中进行异步的操作
Action的基本定义
某些情况, 我们确实希望在Vuex中进行一些异步操作, 比如网络请求。此时就用到了action
Action类似于Mutation, 但是用来代替Mutation进行异步操作的
Action的基本使用代码如下:
- context:
- context是和store对象具有相同方法和属性的对象.
- 也就是说, 我们可以通过context去进行commit相关的操作, 也可以获取context.state等.
- 但是注意, 这里它们并不是同一个对象(后面学习Modules再具体说)
Action的分发
在Vue组件中, 如果我们调用action中的方法, 那么就需要使用dispatch:
同样的, 也是支持传递payload:
Action返回的Promise
在Action中, 我们可以将异步操作放在一个Promise中, 并且在成功或者失败后, 调用对应的resolve或reject:
139. Vuex:modules的使用详解
认识Module
- Module是模块的意思, 为什么在Vuex中我们要使用模块呢?
- Vue使用单一状态树,那么也意味着很多状态都会交给Vuex来管理.
- 当应用变得非常复杂时,store对象就有可能变得相当臃肿.
- 为了解决这个问题, Vuex允许我们将store分割成模块(Module), 而每个模块拥有自己的states、mutations、actions、getters等
组织模块的代码:
Module局部状态
- 上面的代码中, 我们已经有了整体的组织结构, 下面我们来看看具体的局部模块中的代码如何书写.
- 我们在moduleA中添加state、mutations、getters
- mutation和getters接收的第一个参数是局部状态对象
注意:虽然,我们的doubleCount和increment都是定义在对象内部的。但是在调用的时候,依然是通过this.$store
来直接调用的。
Actions的写法
actions的写法呢? 接收一个context参数对象
局部状态通过 context.state 暴露出来,根节点状态则为 context.rootState
如果getters中也需要使用全局的状态, 可以接受更多的参数
140. Vuex:store文件夹的目录组织
项目结构
当我们的Vuex帮助我们管理过多的内容时, 好的项目结构可以让我们的代码更加清晰