手撕Vuex-实现actions方法

经过上一篇章介绍,完成了实现 mutations 的功能,那么接下来本篇将会实现 actions 的功能。

本篇我先介绍一下 actions 的作用,然后再介绍一下实现的思路,最后再实现代码。

actions 的作用是用来异步修改共享数据的,怎么异步修改,这个时候我们回到 Vue 的官方 Vuex 文档中,有如下这么一个图:

手撕Vuex-实现actions方法

从图中可以看出,我们在组件中调用 dispatch 方法,然后 dispatch 方法会调用 actions,然后 actions 中的方法可以通过 commit 会调用 mutations 中的方法,最后 mutations 中的方法会修改 state 中的数据,这就是 actions 的作用。

这里我们先来回顾一下怎么使用 actions,再来实现一遍即可。

  1. 将官方的 Vuex 注释放开
  2. 在 store 中定义 age
  3. 在 mutations 中定义 changeAge 方法
  4. 在 actions 中定义 asyncAddAge 方法 (页面通过 dispatch 调用 actions 中的方法, actions 中的方法通过 commit 调用 mutations 中的方法)

如上是我本次实现的思路,接下来我们来实现代码。

我这里直接贴出代码, 代码中有详细的注释, 代码如下:

1. 略过  2. 定义 age state: {     age: 0 }  3. 在 mutations 中定义 changeAge 方法 /**  * 通过dispatch调用  * @param state 仓库的state  * @param payload 载荷  */ addAge(state, payload) {     state.age += payload; }  4. 在 actions 中定义 asyncAddAge 方法 /**  * 通过dispatch调用  * @param commit 提交  * @param payload 载荷  */ asyncAddAge({commit}, payload) {     // 模拟异步操作     setTimeout(() => {         // 通过commit调用mutations中的方法         commit('addAge', payload);     }, 3000); } 
  1. 在组件中通过 dispatch 调用 actions 中的方法(HelloWorld 组件)
// 显示数据 <p>{{ this.$store.state.age }}</p>  // 调用actions中的方法 <button @click="myFn">我是按钮</button> myFn() {   this.$store.dispatch('asyncAddAge', 10); }, 

npm run serve 启动项目,点击按钮,3 秒后 age 的值加 10,说明 actions 的功能实现了。效果如下图:

手撕Vuex-实现actions方法

到此为止,回顾完成了之后,我们就可以开始实现 actions 的功能了。

actions 的实现思路和 mutations 的实现思路是一样的,首先将官方的 Vuex 注释掉,导入我们自己的 Nuex:

import Vuex from './Nuex' // import Vuex from 'vuex' 

回到我们的 Nuex 文件中,和之前一样先将 actions 保存到 Store 上,我这里单独弄了一个 initActions 方法,代码如下:

// 将传递进来的 actions 放到 Store 上 this.initActions(options); 

initActions 方法的实现如下:

initActions(options) {     // 1.拿到传递进来的actions     let actions = options.actions || {};     // 2.在Store上新增一个actions的属性     this.actions = {};     // 3.将传递进来的actions中的方法添加到当前Store的actions上     for (let key in actions) {         this.actions[key] = (payload) => {             // 4.将actions中的方法执行, 并且将当前Store实例传递过去             actions[key](this, payload);         }     } } 

这里和 mutations 的实现思路是一样的,只是将 mutations 换成了 actions,然后将传递进来的 actions 中的方法添加到当前 Store 的 actions 上,最后将 actions 中的方法执行,并且将当前 Store 实例传递过去。

测试一下看看有没有添加到 Store 上,运行项目,测试结果如下:

手撕Vuex-实现actions方法

可以看到 actions 已经添加到 Store 上了,那么在页面上是通过 dispatch 调用 actions 中的方法,所以我们需要在 Store 上添加 dispatch 方法,代码如下:

dispatch = (type, payload) => {     this.actions[type](payload); } 

这里和 mutations 的实现思路是一样的,只是将 commit 换成了 actions,然后将传递进来的 actions 中的方法执行,并且将当前 Store 实例传递过去。

运行项目,测试结果如下:

手撕Vuex-实现actions方法

Uncaught TypeError: Cannot read properties of undefined (reading 'mutations')

这里报错了,其实这个问题我已经知道错在哪里了,我先带着大家看一下这个调用流程,然后再解决这个问题。

  1. 在组件中调用 dispatch 方法,我传递是的 'asyncAddAge', 10

手撕Vuex-实现actions方法

  1. 在 dispatch 方法中,我拿到了传递进来的 type,也就是 'asyncAddAge', payload 也就是 10, 然后调用了 actions 中的方法

手撕Vuex-实现actions方法

  1. 在 actions 中的方法中,我拿到了传递进来的 payload,也就是 10,在 asyncAddAge 方法中,我调用了 commit 方法,也就是调用了 mutations 中的方法

手撕Vuex-实现actions方法

手撕Vuex-实现actions方法

  1. 在 commit 方法中,我拿到了传递进来的 type,也就是 'addAge', payload 也就是 10, 然后调用了 mutations 中的方法

报错的位置在这里,因为我在 commit 方法中,拿到了传递进来的 type,也就是 'addAge', 代码继续往下执行,执行到 this.mutations[type](payload); this 是 undefined,所以报错了。

正是因为在 actions 中的方法中,我调用了 commit 方法,也就是调用了 mutations 中的方法,在调用时没有告诉 commit 方法,this 是谁,所以才会报错。

那么怎么解决这个问题呢?其实很简单,只需要将之前的 commit 方法改为箭头函数即可,因为改为了箭头函数,this 就是当前 Store 实例了(改为了箭头函数当前在哪里定义的那么 this 就是谁),代码如下:

commit = (type, payload) => {     this.mutations[type](payload); } 

运行项目,测试结果如下:

手撕Vuex-实现actions方法

到此为止,actions 的功能就实现了,接下来我们来回顾一下实现的思路。

  1. 将传递进来的 actions 放到 Store 上
  2. 在 Store 上添加 dispatch 方法
  3. 在 dispatch 方法中,调用 actions 中的方法
  4. 在 actions 中的方法中,调用 commit 方法
  5. 在 commit 方法中,调用 mutations 中的方法(这里就走我们上一篇章的流程了)
发表评论

评论已关闭。

相关文章