1

As the title says, I have a problem catching an error in a Vue method getTodo.
Click on Set incorrect url and then on Get Todo, you can see there is an error in the store as expected, but in Vue when the getTodo promise's then is executed, there's no error. If you select Set correct url then it works fine. Console logs should look like this:

error on store  
error on vue

JavaScript and HTML below:

const store = new Vuex.Store({
    state: {
        todo: '',
        msg: '',
        url: 'https://jsonplaceholder.typicode.com/todos/test',
        correct: false
    },
    mutations: {
        setTodo(state, payload) {
            state.todo = payload;
        },
        setMsg(state, payload) {
            state.msg = payload;
        },
        setCorrect(state) {
            state.url = 'https://jsonplaceholder.typicode.com/todos/1';
            state.correct = true;
        },
        setIncorrect(state) {
            state.url = 'https://jsonplaceholder.typicode.com/todos/test';
            state.correct = false;
        }
    },
    actions: {
        getTodo({ state, commit }) {
            return axios.get(state.url)
                .then(response => {
                    console.log('success on store');
                    commit('setMsg', 'success on store');
                    commit('setTodo', response.data);
                })
                .catch(error => {
                    console.log('error on store');
                    commit('setMsg', 'error on store');
                });
        }
    }
})
new Vue({
    el: '#app',
    data: {
        message: ''
    },
    computed: {
        todo() {
            return store.state.todo;
        },
        msg() {
            return store.state.msg;
        },
        correctUrl() {
            return store.state.correct;
        }
    },
    methods: {
        getTodo() {
            store.dispatch('getTodo').then(() => {
                console.log('success on vue');
                this.message = 'success on vue'
            }).catch((e) => {
                console.log('error on vue');
                this.message = 'error on vue';
            });
        },
        setCorrect() {
            store.commit('setCorrect');
        },
        setIncorrect() {
            store.commit('setIncorrect');
        }
    }
})
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Page Title</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>

<body>
    <div id="app">
        <p>{{ message }}</p>
        <p>{{ todo }}</p>
        <p>Correct url: {{ correctUrl }}</p>
        <button @click="getTodo">Get Todo</button>
        <button @click="setCorrect">Set correct url</button>
        <button @click="setIncorrect">Set incorrect url</button>
    </div>
    
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/vuex@3.0.1/dist/vuex.js"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</body>

</html>
Husam Ibrahim
  • 6,999
  • 3
  • 16
  • 28
hafer
  • 137
  • 1
  • 10

1 Answers1

1

You need to re-throw the error after catching it in your getTodo action ..

actions: {
        getTodo({ state, commit }) {
            return axios.get(state.url)
                .then(response => {
                    console.log('success on store');
                    commit('setMsg', 'success on store');
                    commit('setTodo', response.data);
                })
                .catch(error => {
                    console.log('error on store');
                    commit('setMsg', 'error on store');
                    throw error;
                });
        }
}

const store = new Vuex.Store({
    state: {
        todo: '',
        msg: '',
        url: 'https://jsonplaceholder.typicode.com/todos/test',
        correct: false
    },
    mutations: {
        setTodo(state, payload) {
            state.todo = payload;
        },
        setMsg(state, payload) {
            state.msg = payload;
        },
        setCorrect(state) {
            state.url = 'https://jsonplaceholder.typicode.com/todos/1';
            state.correct = true;
        },
        setIncorrect(state) {
            state.url = 'https://jsonplaceholder.typicode.com/todos/test';
            state.correct = false;
        }
    },
    actions: {
        getTodo({ state, commit }) {
            return axios.get(state.url)
                .then(response => {
                    console.log('success on store');
                    commit('setMsg', 'success on store');
                    commit('setTodo', response.data);
                })
                .catch(error => {
                    console.log('error on store');
                    commit('setMsg', 'error on store');
                    throw error;
                });
        }
    }
})
new Vue({
    el: '#app',
    data: {
        message: ''
    },
    computed: {
        todo() {
            return store.state.todo;
        },
        msg() {
            return store.state.msg;
        },
        correctUrl() {
            return store.state.correct;
        }
    },
    methods: {
        getTodo() {
            store.dispatch('getTodo').then(() => {
                console.log('success on vue');
                this.message = 'success on vue'
            }).catch((e) => {
                console.log('error on vue');
                this.message = 'error on vue';
            });
        },
        setCorrect() {
            store.commit('setCorrect');
        },
        setIncorrect() {
            store.commit('setIncorrect');
        }
    }
})
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Page Title</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>

<body>
    <div id="app">
        <p>{{ message }}</p>
        <p>{{ todo }}</p>
        <p>Correct url: {{ correctUrl }}</p>
        <button @click="getTodo">Get Todo</button>
        <button @click="setCorrect">Set correct url</button>
        <button @click="setIncorrect">Set incorrect url</button>
    </div>
    
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/vuex@3.0.1/dist/vuex.js"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</body>

</html>
Husam Ibrahim
  • 6,999
  • 3
  • 16
  • 28
  • Thanks for your answer, it works as i expected, but i have two more questions. May i have problems in future using that approach? For example if i want to build nested API calls. Second question is about using js promises with axios or it doesn't make any sense? – hafer Nov 04 '18 at 03:54
  • @hafer [Re-throwing](https://javascript.info/promise-chaining#rethrowing) an error in a promise chain is a common pattern. You just have to make sure the [error is handled properly](https://hackernoon.com/promises-and-error-handling-4a11af37cb0e) in the latter stages in the chain. – Husam Ibrahim Nov 04 '18 at 04:28
  • As for axios you do know it's promise based and it's a well designed library so unless there's some pressing need to mix in your own promises I would refrain from doing that lest you unknowingly fall into some [anti-pattern](https://stackoverflow.com/questions/23803743/what-is-the-explicit-promise-construction-antipattern-and-how-do-i-avoid-it) in the process. – Husam Ibrahim Nov 04 '18 at 04:28