Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to return promise from an action? #8

Open
mlanin opened this issue Nov 15, 2018 · 11 comments
Open

How to return promise from an action? #8

mlanin opened this issue Nov 15, 2018 · 11 comments

Comments

@mlanin
Copy link

mlanin commented Nov 15, 2018

In all my projects with vuex I used to call api methods in module's actions, store result in state and then handle result in component method by returning Promise like this:

Component:

{  
  methods: {
    ...mapActions([
      'loadPages'
    ]),
    handleLoad () {
      this.loadPages().then(() => this.$router.push({ name: 'pages' }))
    }
}

Vuex module:

import { load } from '@/api/pages'

const state = {
  pages: []
}

const mutations = {
  LOAD_PAGES (state, pages) {
    state.pages = pages
  }
}

const actions = {
  storeAuthor ({commit}, items) {
    return load().then(pages => commit('LOAD_PAGES', pages))
  }
}

export default {
  state,
  mutations,
  actions
}

It seems like using vuex-electron and createSharedMutations I can't do this anymore, since vuex actions now return undefined.

So how to handle when action was accomplished?

marvinosswald added a commit to marvinosswald/kubeterm that referenced this issue Nov 15, 2018
@ghost
Copy link

ghost commented Dec 1, 2018

how did you solve this problem???

@busheezy
Copy link

busheezy commented Jan 2, 2019

I've been wasting a bunch of time trying to figure out why I can't get this working. I guess this library isn't really in a usable state.

@ktmouk
Copy link

ktmouk commented Jan 4, 2019

In my case,
It was solved by creating a custom plugin.

  1. Create Custom Plugin
// promise-action.js

import promiseIpc from 'electron-promise-ipc' // yarn add electron-promise-ipc

const DISPATCH = 'promise-action-dispatch'

export default (options = {}) => store => {
  function renderer () {
    store.dispatchPromise = (type, payload) =>
      promiseIpc.send(DISPATCH, {
        type,
        payload
      })
  }

  function main (store) {
    promiseIpc.on(DISPATCH, ({ type, payload }) => {
      return store.dispatch(type, payload)
    })
  }

  return process.type === 'renderer'
    ? renderer()
    : main(store)
}
  1. Load Plugin
import Vue from 'vue'
import Vuex from 'vuex'

import { createPersistedState, createSharedMutations } from 'vuex-electron'
import createPromiseAction from './promise-action' // <-- ADD

import modules from './modules'

Vue.use(Vuex)

export default new Vuex.Store({
  modules,
  plugins: [
    createPersistedState(),
    createSharedMutations(),
    createPromiseAction() // <-- ADD
  ],
  strict: process.env.NODE_ENV !== 'production'
})
  1. Use
// Action
const actions = {
  yourAction ({commit}, items) {
    return 'OK'
  }
}

// Component
const response = await this.$store.dispatchPromise('yourAction')
console.log(response) // OK

@cwirz
Copy link

cwirz commented Jan 16, 2019

Thanks for this plugin. I tried it with axios and it works but i get an error message in the renderer console: Unhandled rejection Error: Request failed with status code 400

const actions = {
  login ({commit}, data) {
    return axios.post(getTokenUrl, data)
      .then(r => {
        commit('SET_TOKEN', data)
      })
  },
}

Any idea how to fix this?

@ktmouk
Copy link

ktmouk commented Jan 16, 2019

@cwirz probably, Your sending request failed (url, data or method is invalid). axios/axios#972
You can use .catch for catch the error response.

const actions = {
  login ({commit}, data) {
    return axios.post(getTokenUrl, data)
      .then(r => {
        commit('SET_TOKEN', data)
      })
      .catch(e => {
         // when request failed
         console.log(e)  
      })
  },
}

@cwirz
Copy link

cwirz commented Jan 16, 2019

@ktmouk yeah this kinda worked but i wanted to catch the error in the component from where i dispatch the action:

this.$store.dispatchPromise('auth/login', this.credentials)
  .then(r => {
    this.skip()
  })
  .catch(e => {
    this.error = e.response.data
  })

This time i dont get any error like that anymore so thanks!

@JeroenSormani
Copy link

JeroenSormani commented Jan 18, 2019

Was looking all over the internet looking why my Promise handling wasn't working.. Would be great to have a fix in the package itself without having to manually create the plugin.

@darkman97i
Copy link

darkman97i commented Apr 20, 2019

In my case I'm usign axios and I return the Promise ( okm.$ws.auth.login really is a method what returns the axios post ):

const actions = {
  login({ commit }, userCredentials) {
    return okm.$ws.auth.login(userCredentials.username, userCredentials.password).then(response => {
      const token = response;
      okm.$ws.setToken(token);
      commit('setToken', token);
    });
  }
};

And from the component I'm using in this way ( you can consume the response from the action and the error from the component too ):

methods: {
      ...mapActions('user', ['login'),
      executeLogin() {
        this.login({ username: this.username, password: this.password }).then(response => {
          // Get user data
          ....
        }).catch(error => {
          this.showError(error);
        });
      }
    }

@akodkod
Copy link
Contributor

akodkod commented Aug 29, 2019

#44

@namila007
Copy link

@ktmouk thank you so much for your solution. I was searching why I cant get the async replies using dispatch. If you can please add it as a plugin to npm, so others can easily use this. thanks again :)

@ferm10n
Copy link

ferm10n commented Jun 20, 2021

The heart of the issue is that there's no way for the result of an action to be passed back to the renderer process.
This was my approach to changing the library, although it needs electron > 7 to use invoke...

ferm10n@ec3bab4#diff-5ea1fc93a80776ff21fc637ff5967a710b3effa4720112d9b09617662fb2f8afR46-R107

Also I think I might have been dumb and could have just used event.reply() and not changed the required electron version
just kidding, I thought it would be easy like socket.io does it... I guess there isn't a way to provide a callback in the renderer process? Which means getting the responses from main to resolve the right actions in the renderer would get hella weird.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants