Using Vuex State with v-model Directive

Typically, when you’re building a Vue component and make use of the v-model directive on a component, you’re working with state that is meant to be local to that component. You might be computing other properties based off that property or you might even be watching for changes to perform some action local to that component. But it’s not terribly common to store that intermediate state in a central store (Vuex). The solution to this use case is obvious once you see it but first, I want to cover the two options that might come to mind but aren’t the best available.

v-model Combined with Watchers

One hacky option would be to continue using local state and link it to the store via watchers.

<input v-model="myInput">
computed: {
    storedInput () {
        return this.$store.state.myInput
    }
},
watchers: {
    storedInput (newValue) {
        this.myInput = newValue
    },

    myInput (newValue) {
        this.$store.commit('setMyInput', newValue)
    }
},

v-bind:value and Change Handler

A better but still verbose solution to the problem would be to replicate the v-model behavior with v-bind:value and listening to events first on the element. This way you can create your own update code without using watchers.

<input :value="myInput" @input="updateMyInput">
computed: {
    myInput () {
        return this.$store.state.myInput
    }
},
methods: {
    updateMyInput (e) {
        this.$store.commit('setMyInput', e.target.value)
    }
}

v-model with Two-Way Computed Property

Finally, the best option (something I missed on my first run through the Vuex docs) is the suggestion to use Vue’s two-way computed properties in this scenario. Of course! This option is less verbose but more importantly plugs into the reactivity of Vue much more nicely.

<input v-model="myInput">
computed: {
    myInput: {
        get () {
            return this.$store.state.myInput
        },
        set (newValue) {
            this.$store.commit('setMyInput', newValue)
        }
    }
}