web-dev-qa-db-fra.com

Retourner les promesses des actions Vuex

J'ai récemment commencé à migrer de jQ vers un framework plus structuré, comme VueJS, et j'adore!

Sur le plan conceptuel, Vuex a été un peu un changement de paradigme pour moi, mais je suis sûr de savoir de quoi il en retourne maintenant, et de le comprendre! Mais il existe quelques petites zones d'ombre, principalement du point de vue de la mise en œuvre.

Celui-ci me semble bien, mais je ne sais pas si cela contredit le flux de données Vuex cycle du flux de données unidirectionnel.

Fondamentalement, est-il considéré comme une bonne pratique de retourner un objet de type promesse après une action? Je les traite comme des enveloppes asynchrones, avec des états d’échec et autres, cela semble donc être un bon moyen de retourner une promesse. Au contraire, les mutateurs ne font que changer les choses et sont les structures pures d'un magasin/module.

89
Daniel Park

actions dans Vuex sont asynchrones. Le seul moyen de permettre à la fonction appelante (initiateur de l'action) de savoir qu'une action est terminée est de retourner une promesse et de la résoudre plus tard.

Voici un exemple: myAction renvoie un Promise, passe un appel http et résout ou rejette le Promise plus tard, de manière asynchrone.

actions: {
    myAction(context, data) {
        return new Promise((resolve, reject) => {
            // Do something here... lets say, a http call using vue-resource
            this.$http("/api/something").then(response => {
                // http success, call the mutator and change something in state
                resolve(response);  // Let the calling function know that http is done. You may send some data back
            }, error => {
                // http failed, let the calling function know that action did not work out
                reject(error);
            })
        })
    }
}

Désormais, lorsque votre composant Vue initialisera myAction, il obtiendra cet objet Promise et pourra savoir s'il a réussi ou non. Voici un exemple de code pour le composant Vue:

export default {
    mounted: function() {
        // This component just got created. Lets fetch some data here using an action
        this.$store.dispatch("myAction").then(response => {
            console.log("Got some data, now lets show something in this component")
        }, error => {
            console.error("Got nothing from server. Prompt user to check internet connection and try again")
        })
    }
}

Comme vous pouvez le voir ci-dessus, il est très avantageux pour actions de renvoyer un Promise. Sinon, l'initiateur de l'action n'a aucun moyen de savoir ce qui se passe et quand la situation est suffisamment stable pour afficher quelque chose sur l'interface utilisateur.

Et une dernière note concernant mutators - comme vous l'avez souligné à juste titre, ils sont synchrones. Ils changent de choses dans le state, et sont généralement appelés de actions. Il n'est pas nécessaire de mélanger Promises avec mutators, car le actions gère cette partie.

Edit: Mon point de vue sur le cycle Vuex du flux de données unidirectionnel:

Si vous accédez à des données telles que this.$store.state["your data key"] dans vos composants, le flux de données est unidirectionnel.

La promesse de l'action consiste uniquement à informer le composant que l'action est terminée.

Le composant peut soit extraire des données de la fonction de résolution de promesse dans l'exemple ci-dessus (non unidirectionnel, donc déconseillé), soit directement de $store.state["your data key"] qui est unidirectionnel et suit le cycle de vie des données de vuex.

Le paragraphe ci-dessus suppose que votre mutateur utilise Vue.set(state, "your data key", http_data), une fois l'appel http terminé dans votre action.

190
Mani

Juste pour une information sur un sujet fermé: vous n’avez pas à créer de promesse, axios en renvoie une elle-même:

Réf.: https://forum.vuejs.org/t/how-to-resolve-a-promise-object-in-a-vuex-action-and-redirect-to-another-route/18254/ 4

Exemple:

export const loginForm = ({commit},data) => {
        return axios.post('http://localhost:8000/api/login',data).then((response) => {
            console.log(response);
            commit('logUserIn',response.data.data);
        }).catch((error) => {
            commit('unAuthorisedUser',{
                error:error.response.data
            })
        })
};

Un autre exemple:

    addEmployee({ commit, state }) {       
        return insertEmployee(state.employee).then(result => {
            commit('setEmployee', result.data);
            return result.data // resolve 
        }).catch(err => {           
            throw err.response.data // reject
        });
    },
20
Anoop.P.A

Actions

ADD_PRODUCT : (context,product) => {
  return Axios.post(uri, product).then((response) => {
    if (response.status === 'success') {  
      context.commit('SET_PRODUCT',response.data.data)
    }
    return response.data
  });
});

composant

this.$store.dispatch('ADD_PRODUCT',data).then((res) => {
  if (res.status === 'success') {
    // write your success actions here....
  } else {
     // write your error actions here...
  }
})
6

TL: DR; retourne les actions promises de votre part uniquement lorsque cela est nécessaire, mais DRY en enchaînant les mêmes actions.

Pendant longtemps, j'ai aussi pensé que les actions renvoyées contredisaient le cycle de flux de données unidirectionnel Vuex.

Mais, il y a Edge CASES où le retour d'une promesse de vos actions pourrait être "nécessaire".

Imaginez une situation dans laquelle une action peut être déclenchée à partir de 2 composants différents, chacun gérant le cas d'échec différemment. Dans ce cas, il faudrait passer le composant appelant en tant que paramètre pour définir différents indicateurs dans le magasin.

exemple muet

Page où l'utilisateur peut modifier le nom d'utilisateur dans la barre de navigation et dans la page/profil (qui contient la barre de navigation). Les deux déclenchent une action "changement de nom d'utilisateur", qui est asynchrone. Si la promesse échoue, la page doit uniquement afficher une erreur dans le composant pour lequel l'utilisateur tente de modifier le nom d'utilisateur.

Bien sûr, c’est un exemple stupide, mais je ne vois pas comment résoudre ce problème sans dupliquer le code et passer le même appel en 2 actions différentes.

0
srmico