Should we use v-model to modify Vuex store?

27,029

Solution 1

https://vuex.vuejs.org/guide/forms.html

When using Vuex in strict mode, it could be a bit tricky to use v-model on a piece of state that belongs to Vuex.

The "Vuex way" to deal with it is binding the <input>'s value and call an action on the input or change event.

Be sure to check out the simple "Two-way Computed Property" example on that page:

<input v-model="message">

computed: {
  message: {
    get () {
      return this.$store.state.obj.message
    },
    set (value) {
      this.$store.commit('updateMessage', value)
    }
  }
}

Solution 2

I think another good option which hasn't been mentioned in any answer here is to use vuex-map-fields. In fact, the library author has written a very nice explanation for the library's usefulness. As per its GitHub page, to use the library you can do something like this:

In your Vuex Store, you can have a snippet similar to this:

import Vue from 'vue';
import Vuex from 'vuex';

import { getField, updateField } from 'vuex-map-fields';

Vue.use(Vuex);

export default new Vuex.Store({
  // ...
  modules: {
    fooModule: {
      namespaced: true,
      state: {
        foo: '',
      },
      getters: {
        getField,
      },
      mutations: {
        updateField,
      },
    },
  },
});

And in your component code, you can have something along the lines of this:

<template>
  <div id="app">
    <input v-model="foo">
  </div>
</template>

<script>
import { mapFields } from 'vuex-map-fields';

export default {
  computed: {
    // `fooModule` is the name of the Vuex module.
    ...mapFields('fooModule', ['foo']),
  },
};
</script>

Additional examples for various use cases are shown in the library's GitHub repository that I linked to in the first sentence of this answer.

Solution 3

Above solution can also implemented with mutations:

<template>
  <input v-model="message">
</template>

<script>
import { mapMutations, mapState } from 'vuex';

export default {
  computed: {
    ...mapState({messageFromStore: 'message'}),
    message: {
      get() {
        return this.messageFromStore;
      },
      set(value) {
        this.updateMessage(value);
      }
    }
  },
  methods: {
    ...mapMutations('updateMessage')
  }
};
</script>

Solution 4

My Solution to this was to use a getter to set value and @input to call the mutation.

<input
  type="text"
  :value="$store.getters.apartmentStreet"
  @input="value => $store.commit('apartmentValue', { handle: 'street', value })"
>

getters.js:

export default {
  apartmentStreet: state => state.apartment.street,
};

mutations.js

export default {
  apartmentValue(state, payload) {
    let oldValue = state.apartment[payload.handle];
    let newValue = payload.value;
    if (newValue !== oldValue) state.apartment[payload.handle] = payload.value;
  }
};

If you use this method be sure to check which event you want.

Solution 5

I use this solution.

data() {
  return {
    formData: {
      username: '',
      email: '',
      bio: {
        firstName: '',
        lastName: ''
      },
      games: ['civ4', 'caesar3', 'homeworld', 'cataclysm'],
         
    }
  }
},
computed: {
  ...mapGetters({   //or mapState
    user: 'users'
  })
},
watch: {
  user(newValue) {
    this.formData.username = newValue.name;
    this.formData.email = newValue.email;
    this.formData.bio.firstName = newValue.bio.firstName;
    this.formData.bio.lastName = newValue.bio.lastName;
    this.formData.games = newValue.games.map(x=> { return x });
  }
},
beforeCreate: fucntion() {
  this.$store.dispatch('getUser');
}

And then you just regularly use v-model. It is important to make deep copy of object from store, like using map for array, and how i did stuff with object inside.

And, also you need to have initiated this user object in store also, with empty fields.

Share:
27,029
Krzysztof Kaczyński
Author by

Krzysztof Kaczyński

Updated on July 09, 2022

Comments

  • Krzysztof Kaczyński
    Krzysztof Kaczyński almost 2 years

    Hello I am beginner in Vue and I do have a problem that's really bugging me. I am wondering should we use v-model directive to modify vuex store? Vuex says that we should modify vuex store only by mutations but v-model makes everything easier and shorter.(I am asking because i couldn't find clear answer)

  • Krzysztof Kaczyński
    Krzysztof Kaczyński about 5 years
    yes, but why we shouldn't use v-model (because we should modify vuex store only by mutations) but what v-model is doing that it is not recommended to modify vuex store by v-model directive?
  • Tristan De Oliveira
    Tristan De Oliveira about 5 years
    << The benefit of this convention is we can record all state mutations happening to the store and implement advanced debugging helpers such as mutation logs, snapshots, and history re-rolls / time travel. >> : vuejs.org/v2/guide/state-management.html
  • Kwesi Smart
    Kwesi Smart over 4 years
    I guess you mean <input v-model="tab"> on line 2
  • Eggon
    Eggon about 4 years
    @TristanDeoliveira What if someone doesn't care about the "advanced debugging helpers", because he's building a simple app? Will v-modelling store directly cause any other problems? When I started learning Vue I did use v-models to link store directly (I used getters though not state object) and I don't remember having any problems. Isn't the best practice an overkill for small apps?
  • Jan Veselý
    Jan Veselý over 3 years
    Would this work for more complex data in the message?
  • Mirko
    Mirko about 3 years
    @Eggon agreed, vuex should handle this behind the scenes...
  • Christian Johansen
    Christian Johansen over 2 years
    Thx for the solution. I Modified it to use dispatch("SomeAction") rather than commit. Since using an action is the recommended way to do it.