Vuex: Dispatch an action always return a Promise?

Created on 19 Oct 2016  ·  11Comments  ·  Source: vuejs/vuex

I find that normal function (not async) in action return a Promise,is this a bug?

actions: {
  actionA ({ commit }) {
    return 1;
    })
  }
}

Then store.dispatch('actionA') got a Promise, there is no difference with:

actions: {
  async actionA ({ commit }) {
    return 1;
    })
  }
}
2.0

Most helpful comment

A couple of points:

  1. Is that a real problem?
  2. actions should never have real return values that your app relies on, their only side-effect should be mutations. If you rely on a sync return value, you are not following their intended use.
  3. Therefore, if they are sync but return a promise, that should not be a _problem_ in any scenario.
  4. But _why_ do we return a promise for every action?

It makes it easier to compose actions that _might_ have async side-effects which should return a Promise (like and API call that's only nessessary if condition XY). In those cases, if there was no API call and no Promise resulting from that, you would otherwise have to manually create and return a Promise in those actions to get predictable behaviour.

async await solves this nicely, but it's not in the standard yet so we won't rely on people using it.

All 11 comments

No, this is intended behaviour:

https://github.com/vuejs/vuex/blob/dev/src/index.js#L300-L302

I can't understand a sync action should be wrapped an async action,I writen a sync action then use with await like this:

actions: {
  actionA ({ commit }) {
    return 1;
    })
  }
}

another action:

actions: {
  async actionB ({ dispatch }) {
    await dispatch('actionA');
    })
  }
}

Doesn't it look strange?

why not like this:

actions: {
  actionA ({ commit }) {
    return 1;
    })
  }
  async actionB ({ commit }) {
    return 1;
    })
  }
  async actionC ({ dispatch }) {
    const a = dispatch('actionA');
    const b = await dispatch('actionB')
    })
  }
}

@yyx990803

A couple of points:

  1. Is that a real problem?
  2. actions should never have real return values that your app relies on, their only side-effect should be mutations. If you rely on a sync return value, you are not following their intended use.
  3. Therefore, if they are sync but return a promise, that should not be a _problem_ in any scenario.
  4. But _why_ do we return a promise for every action?

It makes it easier to compose actions that _might_ have async side-effects which should return a Promise (like and API call that's only nessessary if condition XY). In those cases, if there was no API call and no Promise resulting from that, you would otherwise have to manually create and return a Promise in those actions to get predictable behaviour.

async await solves this nicely, but it's not in the standard yet so we won't rely on people using it.

@LinusBorg Thanks for your answers, I disagree with you about that actions should never have real return values,let's think in if action returns a real value.

  1. What value could be returned in the actions? The value must be transient or a message between actions. For example, not all of the origin data is came from the server, actionsA add a message then return a message id, actionB delete message by a message id, the component which dispatch those actions don't care about the message id.
  2. Another usage, we can get more status info for actions in component, if actions should never have real return values, we only know about the actions is done or error by Promise status, but if actions return values, then we can get more info from the actions returned.
  3. async/await will become the standard.

I hope you can consider my suggestion

What value could be returned in the actions

No values should be returned from actions, it defeats the purpose of central state management.
Always use store getters (or access store itself) for actual values.

@fnlctrl 我感觉我用英文描述的不够清楚,我用中文解释一下为什么我认为action可以有返回值,首先是什么数据需要被跟踪,不是说有一个中心仓库,所有的数据都要往里塞,一些瞬时的数据,根本没必要跟踪,我描述一个场景,有个组件用来展示一组信息,他绑定的是一个vuex里state.msg_list,所以有个action负责增加一个信息,有个action用于删除信息,如何确认我要删除哪一个信息,所以增加信息的action可以返回一个msg_id,删除的action可以用这个msg_id去删除对应的数据,代码大概这个样子

actions: {
  add ({ commit }, msg) {
    const id = new IDMaker()
    commit('add', {id, msg})
    return id;
    })
  }
  delete ({ commit }, id) {
    commit('delete', {id})
    })
  }
  actionC ({ dispatch }) {
    const id = dispatch('add');
    ...
    dispatch('delete',{id})
    })
  }
}

一些瞬时的数据,根本没必要跟踪

那别用vuex,直接存组件本地状态。

有个action用于删除信息,如何确认我要删除哪一个信息,所以增加信息的action可以返回一个msg_id,删除的action可以用这个msg_id去删除对应的数据

UI上总要让用户选择删哪个信息的吧。所以UI上调用删除的那个函数把信息对象的id传给actionC就可以了。

@LinusBorg What about a scenario where you want to redirect using vue-router following an action which saves some entity? Let's say you need the freshly stored entity's id to use as a parameter in the this.$router.push call. Isn't it justified to return the new id from the action (via a Promise) in such a case ?
Cheers!

I also have a vuex action that

  1. adds a record to the store with a random ID
  2. returns that generated ID of the new record

So I can use it in the front-end as per this example:

const id = await this.$store.dispatch('records/insert', { name: 'Elvis' })

I don't mind writing await to be able to get the ID back from the action, because the ID generation is instant anyway.
However when @LinusBorg said:

actions should never have real return values that your app relies on, their only side-effect should be mutations. If you rely on a sync return value, you are not following their intended use.

I got a bit worried there might be a better way this _should_ be done...?
Is there any advice on a better approach in the case I portray here?

Was this page helpful?
0 / 5 - 0 ratings