Search code examples
javascriptvuejs2vuex

Why does the data change when the state is updated?


I'm using vue with vuex, and I just spent hours tracing the problem. Maybe you could help.

My question is why does after I create a new team using newTeam method from CreateTeam.vue, the listOfTeams from my Team.vue was also updated?

  • I never made a subscribe or watch or any watcher in my Team.vue. Why does the listOfTeams get updated when I add a new team?
  • Is this exact behavior of vuex? Please enlighten me.

Here is my Team.vue

data() {
    return { listOfTeams: [] }
},

methods: {
    loadRecord: async function() {
        const response = await this.$store.dispatch("teams/load");
        this.$store.commit("teams/intitialize", response.data);
        this.listOfTeams = response.data;
    }
},

CreateTeam.vue

methods: {
    newTeam: async function() {
        const response = await this.$store.dispatch("team/store", formData);
        this.$store.commit("teams/add", response.data);
    }
}

And here teams.js (module) that I'm using

const state = { record: {}, };
const actions = {
    store({commit,state}, payload) { return httpFile().post('/teams', payload); },
    
    load({ commit, state }, payload = "") { return http().get("teams" + payload); }
};

const mutations = {
    intitialize(state, payload) { state.record = payload.data.data; },
    
    add(state, payload) { state.record.unshift(payload.data); },
};

Solution

  • Javascript is a reference-based language (the simplest way to think to it is that all variables and members are pointers).

    This means for example

    let x = [];
    let a = {y: x}; // Doesn't make a copy of x
    console.log(a.y.length); // output is 0
    x.push(10);
    console.log(a.y.length); // output is 1
    

    a.y was empty just after creation, but the member is still pointing to the same array as x, so adding elements to x also adds elements to a.y because they're both pointers to the same object.

    In your code

    this.listOfTeams = response.data;
    

    is not making a copy of response.data thus if that object is modified (e.g. it is emptied and new values are added to it instead of creating a new fresh array) then your member will be changed too.

    To solve you can write:

    this.listOfTeams = response.data.slice();
    

    This way your member class will have its own array and won't be dependent on some other code messing with response.data after you assigned it.