Search code examples
javascriptvue.jsvuex

Vuex map state undefined when it's called from component


So, I attempting to update some data from component every time the state in vuex not null. I set up an API routes with laravel that returns user information after they logged in.

API routes:

Route::group(['middleware' => ['auth:api']], function () {
    Route::get('profil', 'Api\UserController@profil')->name('profile'); // will returning user info
}

Vuex:

export default new Vuex.Store({
    state: {
        token: localStorage.getItem('token') || "",
        user: {}
    },
    getters: {
        isAuth: state => {
            return state.token != "" && state.token != null
        }
    },
    mutations: {
        SET_TOKEN(state, payload) {
            state.token = payload
        },
        SET_AUTH_USER(state, payload) {
            state.user = payload
        }
    }
})

So in my App.vue, in created method, I commit SET_AUTH_USER with the http response as the payload if the token was exist.

App.vue:

<template>
  <div id="app-layout">
    <section-advices></section-advices>
</template>

<script>
    import SectionAdvices from "./SectionAdvices"


    export default {
        name: "app-layout",
        components: {
            SectionAdvices
        },
        created() {
            if (this.$store.state.token !== (null || "")) { //check token in vuex state
                this.$http
                    .get("/profil")
                    .then(res => {
                        if (res.status === 200) {
                            this.$store.commit("SET_AUTH_USER", res.data.data); //set $store.state.user with response
                        } else {
                            this.$store.commit("SET_AUTH_USER", null); // set with null
                        }
                     })
                     .catch(err => {
                         console.log(err);
                     });
            }
        }
    }
</script>

so far, everything works fine. every time I refresh the page, as long as there's a token in my local storage, the user object will always have the user information.

SectionAdvices.vue:

<template>
    <section class="advices">
        <input type="text" v-model="name">
        <input type="text" v-model="email">
    </section>
</template>

<script>
    import { mapState, mapGetters, mapActions, mapMutations } from "vuex";
        export default {
            name: "section-advices",
            data(){
                return{
                    name: null,
                    email: null
                }
            },
            computed:{
                ...mapState(["user"]),
                ...mapGetters(["isAuth"]),
            },
            created() {
                if(this.isAuth) { //its returning true. the codes below was executed
                    this.name = this.user.name // gives name data with "undefined"
                    this.form.email = this.user.email // it's "undefined" too
                 }
             }
        }
</script>

Both name and email in SectionAdvices component was set as "undefined" although in Vue Dev tools, the user object does have these values. Did I call the api in App.vue inside wrong life cycle?


Solution

  • I found th solution, which is:

    as what @dreijntjens suggested, I added watcher in my "SectionAdvices.vue"

    ...
    watch: {
        // watching for store.state.user changes
        user: {
            handler: "fillForm", // call the method
            immediate: true // this watcher will exec immediately after the comp. created
        }
     },
     methods: {
        fillForm() {
            if(this.isAuth) { // this is not necessary, just want to make sure. Once isAuth === true, codes below will be executed
                this.form.name = this.user.name
                this.form.email = this.user.email
            }
        }
     }
    

    So, the real problem is, when SectionAdvices.vue created and fetching data, store.state.user still an empty object. My API calls runs after this step, which is pointless. So, it's true I need watcher, to see any changes in user state and update the local data inside its component after that.