Reputation: 751
I am using Vuex + axios, I want to know the best practice in handling errors for vuex + axios. What I am doing now is that when I request using axios and it returns an error, it will be committed in mutation and update my state. What I want to do is, If there's an response error from my request it will return to my component so that I can handle the error much faster.
Like in angular, there's a dependency injection and the response will return to the component.
Upvotes: 29
Views: 60058
Reputation: 7949
Let me tell you the approach, I used for error logging is this. By this you can handle all vue error by on code.
window.onerror = function (message, source, lineno, colno, error) {
/// what you want to do with error here
};
This is a global error handler for the browser. If any error comes uncaught that can be handle by this.
Also, if you want to handle your error. You can do this.
axios.get('/user?ID=12345')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
// when you throw error this will also fetch error.
throw error;
});
If you want to look on vue for error handling you can go for. https://v2.vuejs.org/v2/api/#errorHandler
Vue.config.errorHandler = function (err, vm, info) {
// handle error
// `info` is a Vue-specific error info, e.g. which lifecycle hook
// the error was found in. Only available in 2.2.0+
}
Let me give you a link where window.onerror is used
https://github.com/stacktracejs/stacktrace.js/
Upvotes: 5
Reputation: 1877
import {onErrorCaptured, ref} from "vue";
setup(){
let errors = ref(null)
onErrorCaptured((error)=>{
// checking for server response first
errors.value = error.response?Object.values(error.response.data)[0]:error.message
})
return{errors}
}
Upvotes: 1
Reputation: 402
Add "last load" state into Vuex, and watch for changes in root.
This may look heavy and complicated, but it's logical and separates components well.
Bonus: you'll know instantly if you have loaded your data and was the attempt successful!
Upvotes: 0
Reputation: 1303
I just use the catch. The same thing I was using before I switched to vuex. It's probably the most universal and well documented solution and lets me continue to insert my errors into the html of the components like I was doing before. It also lets me continue to use my loading = true, loading = false html animation.
So I end up with 3 state properties, data, error, and loading. It seems to work for me. Your mileage may vary. I am also using vuex modules and namespacing but here is a simplified example without that
//somevuexstore.js
actions: {
fetchData(context) {
axios
.get("api/someendpoint")
.then(response => {
context.commit('loading')
context.commit('organizations', response.data)
}).catch(error => {
console.log(error.response.data.message || error.message)
context.commit('error', error)
});
},
mutations: {
organizations(state, data) {
return state.organization = data
},
error(state, data) {
return state.error = data
},
loading(state) {
return state.loading = false
},
state= {
organization: [],
error: '',
loading: true
}
Then in my component.vue it's very similar to the way I was doing it before, just with the added computed properties.
computed: {
...mapState({
getError: 'error',
getLoading: 'loading',
getAllOrg: 'organization',
}),
}
mounted() {
this.$store.dispatch('fetchData')
}
And my html would be stuff like this.
<tr v-for="value in getAllOrg" :key="value.id">
<td>{{ value.id }}</td>
<td>{{ value.email }}</td>
<td>{{ value.name }}</td>
<td>{{ value.['created-at'] | formatDate }}</td>
</tr>
I insert the error messages where appropriate
<div v-if="getError" class="error">
<p>{{ getError }}</p>
</div>
For loading animation I use vue spinners package inserted into html where appropriate.
<div v-if="getLoading" style="height:37px;">
<p>
<bar-loader class="custom-class" color="#c2c2c2"
getLoading="getLoading"
:width="130"></bar-loader>
</p>
Upvotes: 6
Reputation: 41
You can use event bus, like this
import Vue from 'vue'
export const EventBus = new Vue();
and then trigger error
axios.get(...)
.catch(function (error) {
EventBus.$emit('error', error)
});
Upvotes: 1
Reputation: 165059
Have your cake and eat it too. Assuming you are already using an interceptor...
axios.interceptors.response.use(function (response) {
return response;
}, function (error) {
store.commit('ERROR', error) // just taking some guesses here
return Promise.reject(error) // this is the important part
})
This will keep the promise rejection going back to the caller so in your component, something like...
axios.whatever(...).then(res => {
// happy days
}, err => {
// oh noes!
})
Upvotes: 27
Reputation: 1762
vue method (mycomponent.js)
async YourAsyncMethod() {
const payload = {key: "var"}
const result = await axios
.post('/your/api/endpoint', payload)
.catch(e => {
console.log(e.message)
});
}
yourMethod() {
// start axios logic
const payload = {key: "var"}
axios
.post('/your/api/endpoint', payload)
.then(response => {
console.log(response.data)
// start state action logic
this.$store
.dispatch('yourAction', payload)
.then(add => {
console.log('success mutation!');
})
.catch(error => {
// error = Error object,
console.log('error mutation:',error.message);
console.log(error) // to se full error object
});
})
.catch(error => {
console.log('error axios request', error.data)
});
}
with state actions (store/actions.js)
yourAction(){
const some_logic = false;
if (!some_logic) {
// when return a Promisse.reject
//you can get error with catch(e) from youtMethod
return Promise.reject(new Error("Impressora já adicionada"))
}
context.commit('MUTATION_METHOD', payload);
}
with axios
http
.post('/your/api/endpoint', payload)
.then(response => {
console.log(response.data)
})
.catch(error => {
console.log('error', error.data)
});
Upvotes: 0
Reputation: 633
I have come to the conclusion that they can not always exists general methods for handling errors, so they must be somehow coupled to the context. Is a good thing to have separate api files, but mediate this with the mention above. I have separate api files and I am doing the following:
//comments-api.js
export default {
get (url, handler){
//return the promise to further possible chains
return axios.get(url)
.then( response => handler.success(response.data) )
.catch( error => handler.serverDownOrUnexpected(error.response) )
},
}
//comments.js - vuex module
import $comments from './../../services/api/comments-api'
...
actions: {
$comments.get(url, {
success: (data) => commit('success_handler', data),
serverDownOrUnexpected: (error) => commit('unexpected', error)
//so on...
})
}
...
in this approch, whenever I want to change the way certain errors are handled, I have to make changes just in one place, plus benefits of decoupled code.
Upvotes: 0