Vuex doesn't really restrict how you structure your code. Rather, it enforces a set of high-level principles:
As long as you follow these rules, it's up to you how to structure your project. If your store file gets too big, simply start splitting the actions, mutations and getters into separate files.
For any non-trivial app, we will likely need to leverage modules. Here's an example project structure:
To enable strict mode, simply pass in strict: true
when creating a Vuex store:
const store = new Vuex.Store({ // ... strict: true })
In strict mode, whenever Vuex
state is mutated outside of mutation handlers, an error will be thrown. This ensures that all state mutations can be explicitly tracked by debugging tools.
Do not enable strict mode when deploying for production! Strict mode runs a synchronous deep watcher on the state tree for detecting inappropriate mutations, and it can be quite expensive when you make large amount of mutations to the state. Make sure to turn it off in production to avoid the performance cost.
Similar to plugins, we can let the build tools handle that:
const store = new Vuex.Store({ // ... strict: process.env.NODE_ENV !== 'production' })
The above code dynamically detects if the environment is production. If it is, the strict mode is disabled. Otherwise it is enabled. Btw, what is process
here?
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
:
<input v-model="obj.message">
Assuming obj
is a computed property that returns an Object from the store, the v-model
here will attempt to directly mutate obj.message
when the user types in the input. In strict mode, this will result in an error because the mutation is performed directly without commiting mutation.
To deal with the above problem you can use the following approach -
<input :value="message" @input="updateMessage"> // ... computed: { ...mapState({ message: state => state.obj.message }) }, methods: { updateMessage (e) { this.$store.commit('updateMessage', e.target.value) } } // Mutation Handler -- mutations: { updateMessage (state, message) { state.obj.message = message } }
The above approach uses v-bind
instead of v-model
. And Whenever we type something, the updateMessage
is called which mutates the obj
object.
But the above approach is little bit verbose and if there's many inputs, the code gets messier. Also, we will loose many feature from v-model
. There is another alternative way to solve this problem using setter
on computed property.
<input v-model="message"> // ... computed: { message: { get () { return this.$store.state.obj.message }, set (value) { this.$store.commit('updateMessage', value) } } }