web-dev-qa-db-fra.com

Vue.js: gestion des erreurs Nuxt

Luttant un peu pour configurer la gestion des erreurs avec vuex. Il semble y avoir plusieurs façons de le faire et peu de documentation sur la gestion correcte des erreurs. J'ai expérimenté quatre alternatives, mais je n'ai pas encore trouvé de solution satisfaisante.


Alternative 1 - Erreurs de capture et de traitement sur le composant

dans pages/login.vue:

export default {
    methods: {
        onLogin() {
            this.$store.dispatch('auth/login', {
                email: this.email,
                password: this.password,
            }).then(() => {
                this.$router.Push('/home');
            }).catch((error) {
                // handle error in component
            });
        },
    },
}

dans store/auth.js:

export const actions = {
    login({ commit }, { email, password }) {
        return this.$axios.post('/api/login', {
            email,
            password,
        }).then((res) => {
            doSomething(res);
        });
    },
}

PROS

  • Hmm.

CONTRE

  • Erreurs non traitées et stockées dans vuex.
  • Introduit beaucoup de code passe-partout dans les méthodes des composants.

Alternative 2 - Erreurs de capture et de traitement dans vuex

dans pages/login.vue:

export default {
    methods: {
        onLogin() {
            this.$store.dispatch('auth/login', {
                email: this.email,
                password: this.password,
            }).then(() => {
                this.$router.Push('/home');
            });
        },
    },
}

dans store/auth.js:

export const actions = {
    login({ commit }, { email, password }) {
        return this.$axios.post('/api/login', {
            email,
            password,
        }).then((res) => {
            doSomething(res);
        }).catch((error) => {
            // store error in application state
            commit('SET_ERROR', error);
        });
    },
}

PROS

  • L'objet d'erreur est accessible avec vuex depuis n'importe quel composant
  • Pourrait utiliser un composant d'erreur réactif dans la mise en page, qui est révélé lorsque l'état d'erreur change.

CONTRE

  • Je ne sais pas s'il existe un moyen de suivre la source de l'erreur, à partir de quel composant elle a été générée.

Alternative 3 - Détection des erreurs à l'aide d'intercepteurs axios

dans plugins/axios.js:

export default function({ $axios, store }) {
    $axios.onError(error => {
        store.dispatch('setError', error);
    });
}

dans pages/login.vue:

export default {
    methods: {
        onLogin() {
            this.$store.dispatch('auth/login', {
                email: this.email,
                password: this.password,
            }).then(() => {
                this.$router.Push('/home');
            });
        },
    },
}

dans store/auth.js:

export const actions = {
    login({ commit }, { email, password }) {
        return this.$axios.post('/api/login', {
            email,
            password,
        }).then((res) => {
            doSomething(res);
        });
    },
}

PROS

  • Gestion globale des erreurs
  • Pas besoin d'attraper des erreurs dans les vues ou les composants
  • Pas de code de plaque de chaudière

CONTRE

  • Toutes les exceptions sont non gérées, ce qui signifie que les erreurs non axios ne sont pas détectées.

Alternative 4 - Plugin d'erreur personnalisé

J'ai expérimenté l'implémentation d'un plugin personnalisé qui intercepte toutes les exceptions, mais je n'arrive pas à le faire fonctionner.

dans plugins/catch.js:

export default (ctx, inject) => {
    const catchPlugin = function (func) {
        return async function (args) {
            try {
                await func(args)
            } catch (e) {
                return console.error(e)
            }
        }
    };
    ctx.$catch = catchPlugin;
    inject('catch', catchPlugin);
}

dans pages/login.vue:

export default {
    methods: {
        onLogin: this.$catch(async function () {
            await this.$store.dispatch('auth/login', { email: this.email, password: this.password });
            this.$router.Push('/home');
        }),
    },
}

PROS

  • Pas de passe-partout.
  • Toutes les erreurs détectées dans le plugin.

CONTRE

  • Je ne peux pas le faire fonctionner. :(

J'ai l'impression qu'il y a un manque de documentation sur la gestion des erreurs dans vue/nuxt. Quelqu'un pourrait-il avoir la quatrième alternative au travail? Serait-ce idéal? D'autres alternatives? Qu'est-ce qui est conventionnel?

Merci pour votre temps!

30
nomadoda

La raison pour laquelle l'option # 4 ne fonctionne pas est que vous retournez une fonction qui n'est jamais exécutée:

function catchPlugin(outerFunction) {
   return function async innerFunction(args) {
     try {
       const data = await outerFunction(args);
       return { data } 
     } catch (error) {
       return { error }
     }
   }
}

Usage:

const execute = catchPlugin((args) => {
  // do something
})

execute('myArgument');

Comme vous pouvez le voir, vous devez également exécuter la fonction interne pour que votre exemple fonctionne:

onLogin: this.$catch(async function () {
    await this.$store.dispatch('auth/login', { email: this.email, password: this.password });
    this.$router.Push('/home');
})(), // mind the () :-)

Mais ... je crois que la gestion des erreurs dans les composants n'est pas une mauvaise chose, car cela est étroitement lié à votre composant de vue. Par exemple, pensez à un composant de connexion, ce que nous voyons de nos jours est un gestionnaire d'erreur global (toastr) qui affichera un message toast si le nom d'utilisateur/mot de passe est incorrect. D'après mon expérience, ce n'est pas le meilleur comportement, c'est un bon point de départ, mais il serait préférable d'ajouter des messages d'erreur près du composant affichant ce qui s'est exactement passé. Cela signifie que vous devrez toujours ajouter la gestion des erreurs (liée à l'interface utilisateur) dans le composant lui-même.

Nous nous débattons également avec cela dans notre entreprise avec des collègues travaillant sur le même produit. L'un ajoute la gestion des erreurs, l'autre non. La seule solution, à mon avis, est d'éduquer les développeurs à toujours ajouter une gestion des erreurs appropriée. La syntaxe avec async/await n'est pas si mal:

methods: {
   async login (email, password) {
      try {
         await this.$store.dispatch('auth/login', { email, password })
         // do something after login
      } catch (error) {
         // handle error
      }
   }
}

Une dernière chose à propos de votre con: Erreurs non gérées et stockées dans vuex.. Pourquoi est-ce un con? Avez-vous besoin que l'erreur soit disponible à l'échelle mondiale? Ce que je vois beaucoup, c'est que les gens mettent tellement d'inutile état dans vuex qui n'est utilisé que dans le composant lui-même. Ce n'est pas mauvais d'avoir l'état des composants locaux. Comme il s'agit de la connexion, cette erreur ne doit être connue que dans le composant de connexion.

1
Dieterg

Créez une clé error dans l'état de chaque module Vuex. Envoyez ensuite l'erreur pour un composant donné à son module Vuex relatif. Créez ensuite un gestionnaire global pour surveiller les erreurs dans les modules séparés de Vuex et, si l'un est déclenché, affichez l'erreur.

// store/auth.js

export const state = () => {
  return {
    success: null,
    error: null
  }
}

export const actions = {
  async login({ commit }, { email, password }) {
    try {
      const response = await axios.post('/api/login', {
        email,
        password
      })
      commit('SET_SUCCESS', response)
    } catch(err) {
      commit('SET_ERROR', error)
    }
  }
}

export const mutations = {
  SET_SUCCESS(state, payload) {
    state.success = payload
  },
  SET_ERROR(state, payload) {
    state.error = payload
  }
}
// auth.vue

export default {
  methods: {
    onLogin() {
      try {
        await this.$store.dispatch('auth/login', {
          email: this.email,
          password: this.password
        })
        if (this.$store.state.auth.success) this.$router.Push('/home')
      } catch (err) {
        console.log(err)
      }
    }
  }
}
// app.vue

export default {
  created() {
    this.$store.subscribe((mutation, state) => {
      if (mutation.type.includes('ERROR')) {
        // display error in global error output
        console.log(mutation.payload)
      }
    })
  }
}
0
selfagency

Pour répondre au Con de Alternative 2 vous pouvez soit

a) transmettre le nom du composant ou même une référence au composant ou

(b) vous pouvez conserver l'erreur dans l'état du composant qui a effectué l'appel. Ensuite, dans votre composant, vous pouvez vérifier s'il y a une erreur et l'afficher. Pour cela, vous pouvez utiliser un mixin pour renoncer à la nécessité d'une plaque de chaudière.,

en magasin/auth.js:

export const actions = {
    login({ commit }, { email, password }) {
        return this.$axios.post('/api/login', {
            email,
            password,
        }).then((res) => {
            doSomething(res);
            commit('save_to_state', { response: res });
        }).catch((error) => {
            commit('save_to_state', { error });
        });
    },
}
0
Justin Kahn