Photo by Xavier Robin on Flickr

update

The vuex helper function pattern described below is now available as an npm module, vuex-intern.

Intro

Vue.js is my go-to front-end framework these days. I don’t love the component model much more than the React component model, but the ease with which Vuex, Vue’s central state management, integrates with Vue components makes for a very good developer experience. This post is about how I’ve been doing mutations in Vuex.

This post will make more sense to those familiar with Vuex, but for those who aren’t, a mutation in Vuex is a function that mutates the state. The mutation function receives the state and a the value to be put into state. In general, these are simple functions to write. I started to notice that a lot of them ended up looking the same, like setting a value, or adding an item to a list, so I wrote a handful of state mutating functions that can be configured (curried) with the information that differentiates these similar functions.

Example

The simplest of them is called ‘set’. It simply sets a root level property of state.

This first example is how it would look without a state mutator.

const state = {

prop1: null,

prop2: null

} const mutations = {

setProp1 (state, val) {

state.prop1 = val

},

setProp2 (state, val) {

state.prop2 = val

}

}

Let’s refactor to use a state mutator.

const set = key => (state, val) => {

state[key] = val

} const mutations = {

setProp1: set('prop1'),

setProp2: set('prop2')

}

We’ve reduced some of the tedious boilerplate code and simultaneously got rid of the need to test our mutation functions (assuming the state mutators being used have already been tested).

Example Vuex Module Using State Mutators

Here is an example that includes the mutators that I use frequently. The implementations are below the examples.

const state = {

primitive: null,

bool: false,

list: [],

users: []

} const getters = {

// get the user by their id

userById: findByKey('users', '_id')

} const mutations = {

setPrimative: set('primative'),

toggleBool: toggle('bool'),

pushToList: pushTo('list'),

replaceUser: replaceRecordInList('users', '_id')

} const actions = {

...

fetchUser ({ commit }, userId) {

fetch(`https://example.com/users/${userId}`)

.then(res => res.json())

.then(user => commit('replaceUser', user))

}

}

Implementations