Vuex

速查表

Vuex 操作 代码
获取状态 this.$store.state.变量名
同步修改状态 this.$store.commit("命名空间/Mutations 中定义的方法名")
异步修改状态 this.$store.dispatch("命名空间/Actions 中定义的方法名")

杂谈

最近出差去深圳了,所以没太多的经历去写博客,提升自己,摸鱼实在是太爽了,不过兄弟们我还是回来了,咕咕咕!

让我慢慢总结这个吧,毕竟还是重要的东西,之前写项目也在这里绊过跟头,所以这次想在弄懂一些!


简介

我们来看一个比较抽象的概念哈

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以可预测的方式发生变化。

说的比较抽象,其实可以理解为,保存全局状态的地方,改变值得话会有行为记录

比方说,我的登录状态,此状态会贯穿我使用此 app 的所有过程吧?所以这个状态就最好存在 Vuex

再比方说,我登录成功了,此时我要去改变 Vuex 中的变量的状态,然而,我不能直接去修改,而是发出修改的指令,动作


优点

  • 统一管理状态,保证一致性
  • 服务端重构开发
  • 可预测性能:让程序更健壮,出了问题能够反查

安装

vuex 也是个插件,可以通过 vue add vuex 来安装它请添加图片描述
安装完成之后可以看到新添加了些东西啊。

其中的 store 文件夹下的 index.js 的内容如下,我们以后要把变量放在这里的!

在这里插入图片描述


使用

定义变量

还是用举例的方式吧,我现在要管理一个登录的状态,那么我就在 state 里设置个变量

请添加图片描述


获取变量

一般都是在 vue 文件中获取,比较简单

1
2
// 这是在 vue 文件中获取,如果是 html 里就可以 this 省去
this.$store.state.变量名;

这里再讲一下其他地方获取

如果想在其他文件中获取状态,可以先引入 store ,然后再获取,比方说下面这个例子:我在全局路由守卫中获取

首先需要在 js 中导入一下 store

在这里插入图片描述

然后尝试在路由中获取,获取的方法 store.state.变量名,并且写了写逻辑,刷新页面,打印一下!
请添加图片描述

成功获取!


修改状态 Mutations

我们不能直接修改变量值,会报错的,而是通过通知 vuex 一个动作,也就是 mutations 提供的方法,去修改状态
这样的好处上文已经说过,便于统一管理,排查错误。

首先在 mutations 中定义登录、登出的方法

在这里插入图片描述

然后再登录的时候调用该方法:

在这里插入图片描述
最后执行一下看看,成功改变了 vuex 中的变量值(这个打印 islogin 我是放到了全局守卫里了)

请添加图片描述


异步调用 actions

我们先在 actions 中定义好方法,如下图所示,然后通过 dispatch 去调用方法

我们还是举例子,详细的说明请看下图

在这里插入图片描述

再来个动图:

请添加图片描述

是不是清晰了些!


最佳实践

这标题夸张???行吧
在这里插入图片描述

模块化

其实上面改的状态都是属于用户的状态,那我可不可以单独提取出来,变成一个子模块呢?

让我们来提取一下:
在这里插入图片描述

之后的获取、修改变量需要变化一下

获取变量:
在这里插入图片描述
派发事件的方式:
在这里插入图片描述

至于为什么这么修改的,我们可以在官网上找到些蛛丝马迹

在这里插入图片描述


映射方法

探究问题

可以看一下我们修改完之后的获取
在这里插入图片描述

点的实在是太深了,对于我这种懒人,不太友好,有没有较好的处理办法呢?有的,那就是映射出来!


初步认识 mapState()、mapMutation()、mapAction()

这就要接触一下这几个东西了

1
mapState() / mapMutation() / mapAction();

通过这些映射方法可以让大家少敲几个字,避免对 $store 直接访问


使用方法

获取变量:

主要是配合 computed 钩子
在这里插入图片描述
修改变量:

1
2
3
4
// 这两个都行
...mapActions('user', ['login']),
...mapActions(['user/login']),

通过 mapActions 引出,展开,并注册在 methods 里,然后就可以通过 this 来调用了

在这里插入图片描述
整体思路如下

在这里插入图片描述


抛出问题

既然 mutationsactions 可以写同名函数,那么都引用进来,会调用谁的呢?还是老样子啊,想想之后,实验一下!

在这里插入图片描述
实验动图如下:

请添加图片描述

也就是说,同名的方法会被覆盖掉,用最底下的方法。


派生方法 getters

类似 vuex 的计算属性,下面来个欢迎语的实践

在这里插入图片描述

在这里插入图片描述
下面是动图:

请添加图片描述


严格模式

严格模式下,无论何时发生了状态变更且不是由 mutation 函数引起的,将会抛出错误。这能保证所有 的状态变更都能被调试工具跟踪到。

开启严格模式 strict: true

在这里插入图片描述

再看一下报错的情况,虽然说是报错,但是 username 的状态还是改变了。

请添加图片描述


插件

简介

Vuexstore 接受 plugins 选项,这个选项暴露出每次 mutation 的钩子。Vuex 插件就是一个函数,它接收 store 作为唯一参数。

也就是说,每次 mutation 中的方法被调用的时候,都会运行插件里的函数


为什么要用插件

因为 vuex 只是处理窗台的地方,而不是写逻辑的地方


实例:登录永久化

首先需要知道一些比较重要的

1
2
3
4
5
6
7
const myPlugin = (store) => {
// 当 store 初始化后调用
store.subscribe((mutation, state) => {
// 每次 mutation 之后调用
// mutation 的格式为 { type, payload }
});
};

然后可以阅读一下官网,还是比较全面,vuex 官方说明插件

之后再看一下这个逻辑

在这里插入图片描述

最后看一下动图吧:

请添加图片描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 插件源码
import router from "../../router";
/**
* 永久化保存
* - 判断本地缓存是否存在
* - 如果有的话就去设置一下
*/
export default (store) => {
console.log("使用了预处理插件");
if (localStorage) {
const user = JSON.parse(localStorage.getItem("user"));
if (user) {
store.commit("user/login", user);
}
}
store.subscribe((mutation, state) => {
console.log("store.subscribe:>>", mutation);
if (mutation.type === "user/login") {
localStorage.setItem("user", JSON.stringify(state.user));
} else if (mutation.type === "user/logout") {
localStorage.removeItem("user");
router.push("/login");
}
});
};