Search code examples
javascriptvue.jsvuex

Vuex store values getting update without comitting


I started a note taking project with vue-cli and vuex. I have setup everything correctly and everything works fine besides when I add a new note in the vuex store - notelist, it gets added which is fine but when I change the value in the input field my vuex store value also gets updated without committing anything.

here is the code -

<template>
    <div>
       {{title}}
        <input type="text" v-model="note.msg">
        <button v-on:click="addNote()">ADD</button>
    </div> 
</template>
<script>
module.exports = { 
  data() {
    return {  
       title:'Add node', 
       note: {
           msg: this.msg,
           avatar:'wolf'
        }
    }
  }, 
  methods: { 
    addNote(){  
        this.$store.dispatch("updateNotes",this.note);
    }
  },  
}
</script>
<style scoped> 
</style>

When I change the input value after adding my notes, it gets updated in vuex store and also in the other component where I am displaying the list.

what I have tried is this - Instead of making the note.msg as v-model I changed it to msg and data object and computed property has been updated accordingly and it fixed my problem -

<template>
    <div>
       {{title}}
        <input type="text" v-model="msg">
        <button v-on:click="addNote()">ADD</button>
    </div> 
</template>
<script>
module.exports = { 
  data() {
    return {  
       title:'Add node', 
        msg:''
    }
  }, 
  methods: { 
    addNote(){ 
        let note = {
            msg: this.msg,
            avatar:'wolf'
        };
        this.$store.dispatch("updateNotes",note);
    }
  },  
}
</script>
<style scoped> 
</style>

Technically I don't have any problem, just I couldn't get my head around this. I didn't expect that to happen. I've expected the second behaviour not the first one.

enter image description here

EDIT

action.js

const updateNotes = (context, payload) => {
    context.commit('updateNotes', payload);
}

export default {  
    updateNotes,
};

mutation.js

const updateNotes = (state, data) => {
    state.notes.push(data);
}

export default { 
    updateNotes
};

Those are the mutations and actions in my project.


Solution

  • When the updateNote action is dispatched for the first time, it unintentionally creates a connection between the input's v-model (this.note) and the Vuex state notes.

    In JavaScript, objects are passed by reference, which means when you assign a JavaScript object to a variable, it doesn't make a fresh copy, it actually makes both variables point to the same exact object. Changing one changes the other. (This has nothing to do with Vue/Vuex and is true in vanilla JavaScript.)

    So when you pass this.note to Vuex, the item you added is not a unique object, it's the exact same one being used in the component. And it will be like this for every object you add. They all point back to the input because the action keeps passing the reference to this.note.

    The reason it doesn't happen in your fix is because you create a brand new object each time in addNote, and pass that. So it's not connected to anything.

    If you were using Vuex in strict mode, Vuex would throw an error on this:

    Error: [vuex] do not mutate vuex store state outside mutation handlers.

    You can turn on strict mode when you define the store:

    const store = new Vuex.Store({
      strict: true,  // Turning on strict mode
      state: {
        note: null
      }
    }