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
CONTRE
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
CONTRE
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
CONTRE
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
CONTRE
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!
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.
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)
}
})
}
}
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 });
});
},
}