Vuex入门(5)—— 为什么要用Action管理异步操作

摘要:
官方给的定义我没什么意见,事实上我通过mutation异步操作,好像跟用action管理也没什么区别。先来看一个简单的例子,也是我对如果不用Action进行异步操作的一些初步探索。

Action 类似于 mutation,不同在于:

1.Action 提交的是 mutation,而不是直接变更状态。

2.Action 可以包含任意异步操作。

官方给的定义我没什么意见,事实上我通过mutation异步操作,好像跟用action管理也没什么区别。关于为什么要用Action管理异步操作,我会通过一个简单的例子和一个复杂的例子来进行说明,事实上,如果初学者没有考虑到实际场景的复杂情况,会觉得Action根本没有一点软用,这个时候就要把问题想得复杂一些了,然后才能看到Action的作用。

先来看一个简单的例子,也是我对如果不用Action进行异步操作的一些初步探索。

第一步:我非常作死的重写了mutation状态管理器中对状态操作的一些写法,我使用了异步操作代替了之前的操作。

//mutation.js
const increment = (state) =>{
  setTimeout(() =>{
    state.count++}, 1000)
}
const decrement = (state) =>{
  setTimeout(() =>{
    state.count--}, 2000)
  state.count--}
export {increment, decrement}

第二步:试验一下能否成功

<template>
  <div>
    <button @click="decrement">-</button>
    <span>{{count}}</span>
    <button @click="increment">+</button>
  </div>
</template>
<script>import { mapState, mapMutations} from 'vuex'export default{
  computed: {
    ...mapState(['count'])
  },
  methods: {
    ...mapMutations(['increment', 'decrement']),
  }
}
</script>
 
<style>
 
</style>

第三步:发现除了每次操作加减时候有一秒的延时,不管你怎么操作,结果都是正确的,是符合社会主义核心价值观的。

Vuex入门(5)—— 为什么要用Action管理异步操作第1张

第四步:用Action处理异步操作(先得把之前作死改掉的mutation的代码改回来)

//正常的mutation
const increment = (state) =>{
  state.count++}
const decrement = (state) =>{
  state.count--}
export {increment, decrement}
//action.js处理一些异步操作

//Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象
let incrementAsync = (content) =>{
setTimeout(() =>{
content.commit('increment')
}, 1000)
}
let decrementAsync = (content) =>{
setTimeout(() =>{
content.commit('decrement')
}, 1000)
}
export {incrementAsync, decrementAsync}
<template>
  <div>
    <button @click="decrementAsync">-</button>
    <span>{{count}}</span>
    <button @click="incrementAsync">+</button>
  </div>
</template>
<script>import { mapState, mapMutations, mapActions } from 'vuex'export default{
  computed: {
    ...mapState(['count'])
  },
  methods: {
    ...mapMutations(['increment', 'decrement']),
    ...mapActions(['incrementAsync', 'decrementAsync']) //这里用了辅助函数,不了解的可以看这个系列的第二篇文章
}
}
</script>
 
<style>
 
</style>

第五步:测试一下效果,你会感觉跟没有用action直接用mutation的结果一毛一样。再看一下官网说明。

Vuex入门(5)—— 为什么要用Action管理异步操作第2张

所以,官网说的这句话有问题?
确实有问题,因为在mutation中执行异步操作并不会报错,也能正确更改状态,所以并不是所谓的“必须同步执行”这么苛刻,只能说你最好不要这么做。(这里说一句题外话,我初学vuex的时候,大概去年,在mutaition中一旦有异步操作,控制台立马就会有警告,不知道是记错了还是现在删除了这个设定)

上面的例子可能太过简单,以至于Action看起来都发挥不了什么作用。

下面来看一个复杂的例子,这个例子有助于理解为什么要用Action管理异步操作
需求如下

state中存储了一个状态,我们还是复用刚才的count

现在有两个异步操作,他们都能改变count的值

第二个异步操作的条件依赖第一个异步操作的结果,比如第一个异步操作执行了count ++ ,count :0 = >1,第二个异步操作会先判断当前count的值,if(count === 1) { do something...} else { do something...}

当异步操作涉及互相依赖的情况的时候,我们肯定希望被依赖的操作执行完成之后,再执行依赖项,这样能保证程序执行得到正确的结果,但异步操作,如接口访问这种,往往是不能确定执行完成的时间的,

通常你在接口A中得到一个值,a

接口B需要使用这个值结合B接口返回的值进行一些判断操作,if(a&&b){ ... }

这个时候如果B接口执行完毕了,A接口的值还没过来的话,就可能得到错误的结果。 a => undefined

所以这里牵扯到了一个异步操作的顺序执行问题,既然是异步操作问题,基本都会用到ES6的promise函数去解决,有兴趣的可以用看一下我的文章——关于promise的一些使用和原理。

下面我们重写一下代码

//Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象
let incrementAsync = (content) =>{
  return new Promise((resolve, reject) =>{
    setTimeout(() =>{
      content.commit('increment')
      resolve()
    }, 1000)
  })
}
let decrementAsync = (content) =>{
  return new Promise((resolve, reject) =>{
    setTimeout(() =>{
      content.commit('decrement')
      resolve()
    }, 1000)
  })
}
export {incrementAsync, decrementAsync}
})
<template>
  <div>
    <button @click="dec">-</button>
    <span>{{count}}</span>
    <button @click="add">+</button>
  </div>
</template>
<script>import { mapState, mapMutations, mapActions } from 'vuex'export default{
  computed: {
    ...mapState(['count'])
  },
  methods: {
    ...mapMutations(['increment', 'decrement']),
    ...mapActions(['incrementAsync', 'decrementAsync']),
    add () {
      this.incrementAsync().then(() =>{
        this.increment()
      })
    },
    dec () {
      this.decrementAsync().then(() =>{
        //do something
})
    }
  }
}
</script>
 
<style>
 
</style>

关于Action,细枝末节的东西并不想多讲,比如action中的‘载荷’,mapAction辅助函数,promise()函数使用等等,都是之前讲过的,写这篇文章的目的还是想重申一下为什么要用Action管理异步操作,有些人可能觉得如果一种代码可以用另一种看起来可以实现的方式实现的话,就不用去管“规范”的问题了,反而觉得这看起来更像一个“黑客”的做法,从而刻意的追求程序的“自由性”。

我只能说,你可以这么做,但请你善待帮你维护代码的人,因为你的“自由开发”可能让别人完全搞不懂你在写什么,只想骂你是个傻X。

免责声明:文章转载自《Vuex入门(5)—— 为什么要用Action管理异步操作》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇easyui只打开一个tabAndroid菜单详解(五)——使用XML生成菜单下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Vuejs学习笔记(一)

1)    vue.js 的 主要功能 1、模板渲染 2、模块化 3、扩展功能:路由,Ajax 2)    vue.js 模板渲染之双向绑定示例 message 绑定到了 input 对象,所有在input中的值修改了之后,上面的P 标签的显示的内容也会根据其改变。   3)    app.vue 、main.js和 index.html的关联 (1) m...

vue对比其他框架

对比其他框架React React 和 Vue 有许多相似之处,它们都有: 使用 Virtual DOM 提供了响应式(Reactive)和组件化(Composable)的视图组件。 将注意力集中保持在核心库,伴随于此,有配套的路由和负责处理全局状态管理的库。 性能简介 Vue 的性能是优于 React 的。如果你对此表示怀疑,请继续阅读。我们会解释为...

Vue笔记(三):Components—slot

Solt - 内容分发 父组件模板的内容在父组件作用域内编译,子组件模板的内容在子组件作用域内编译。 组件的作用域相互独立,子组件中定义的数据只能在子组件模板内使用,父组件也如此。如果子组件想要使用父组件的数据,需要子组件定义 props 属性来实现。 为了让组件可以组合,我们需要一种方式来混合父组件的内容与子组件自己的模板,这个过程被称为内容分发。Vue...

如何搭建一个vue项目(完整步骤)

转载:https://www.cnblogs.com/hellman/p/10985377.html 一、安装node环境   1、下载地址为:https://nodejs.org/en/   2、检查是否安装成功:如果输出版本号,说明我们安装node环境成功      3、为了提高我们的效率,可以使用淘宝的镜像:http://npm.taobao.or...

vue项目中使用动画钩子给项目添加复杂动画

常规的vue动画实现方式很简单,使用内置的transition组件就能轻易的实现,比如一个组件进场之后其子元素的动画可以这么写 <transition name="normal">      <div class="normal-player">        <div class="top">           ...

Vue.set()和this.$set()源码解析

前言 我们在日常项目开发过程中,有时候我们对数组或者对象进行了一些操作后,发现页面数据没有更新到。这个时候就会有疑问,why? 如果我们在看文档有这样一个api,以下内容: Vue.set()和this.$set()实现原理 Vue.set()的源码:... 这里是省略的代码 import { set } from '../observer/index'...