为什么要用Action管理异步操作

2019-06-13  本文已影响0人  指尖跳动

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>

第三步:发现除了每次操作加减时候有一秒的延时,不管你怎么



第四步:用Action处理异步操作(先得把之前作死改掉的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的结果一毛一样。再看一下官网说明。



所以,官网说的这句话有问题?其实官网给了说明。


下面来看一个复杂的例子,这个例子有助于理解为什么要用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

下面我们重写一下代码

// 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>
上一篇下一篇

猜你喜欢

热点阅读