Skip to content

Instantly share code, notes, and snippets.

@brospars
Last active September 25, 2020 15:07
Show Gist options
  • Save brospars/e2f65d6106b9d9d284abda23108e8753 to your computer and use it in GitHub Desktop.
Save brospars/e2f65d6106b9d9d284abda23108e8753 to your computer and use it in GitHub Desktop.
Generate CRUD mutations and actions for Vuex

Vuex can be quite repetitive to write generic mutations (arrays : set, add, update, delete, literals: update) for each state property. But it's important to keep track of changes inside the store.

So here's a way to generate generic mutations and associated actions :

// book-store.js
const state = {
  id: '',
  title: '',
  authors: [],
  chapters: []
}

const mutations = {
  ...createArrayMutations('authors', 'chapters'),
  ...createLiteralMutations('id', 'title')
}

const actions = {
  ...createArrayActions('authors', 'chapters'),
  ...createLiteralActions('id', 'title')
}

How to use :

// array
store.dispatch('setAuthors', ['J. K. Rowling']) // state.authors : ['J. K. Rowling']
store.dispatch('addAuthors', 'Tolkien') // state.authors : ['J. K. Rowling', 'Tolkien']
store.dispatch('updateAuthors', {index: 1, value: 'J. R. R. Tolkien'}) // state.authors : ['J. K. Rowling', 'J. R. R. Tolkien']
store.dispatch('deleteAuthors', 1) // state.authors : ['J. K. Rowling']

// Literal
store.dispatch('updateId', '28') // state.id : '28'

Inspired by :

export const createLiteralMutations = (...args) => {
return args.reduce((obj, arg) => {
return {
...obj,
[toCamelCase('update', arg)] (state, value) {
state[arg] = value
}
}
}, {})
}
export const createArrayMutations = (...args) => {
return args.reduce((obj, arg) => {
return {
...obj,
[toCamelCase('set', arg)] (state, value) {
state[arg] = value
},
[toCamelCase('add', arg)] (state, value) {
state[arg].push(value)
},
[toCamelCase('update', arg)] (state, data) {
state[arg][data.index] = data.value
},
[toCamelCase('delete', arg)] (state, index) {
state[arg].splice(index, 1)
}
}
}, {})
}
export const createLiteralActions = (...args) => {
return args.reduce((obj, arg) => {
return {
...obj,
[toCamelCase('update', arg)] ({ commit }, value) {
commit(toCamelCase('update', arg), value)
}
}
}, {})
}
export const createArrayActions = (...args) => {
return args.reduce((obj, arg) => {
return {
...obj,
[toCamelCase('set', arg)] ({ commit }, value) {
commit(toCamelCase('set', arg), value)
},
[toCamelCase('add', arg)] ({ commit }, value) {
commit(toCamelCase('add', arg), value)
},
[toCamelCase('update', arg)] ({ commit }, value) {
commit(toCamelCase('update', arg), value)
},
[toCamelCase('delete', arg)] ({ commit }, value) {
commit(toCamelCase('delete', arg), value)
}
}
}, {})
}
// Create component computed property Get and Setter for use in v-model
export const createGetterAndSetter = (module, args) => {
return args.reduce((obj, arg) => {
obj[arg] = {
get () {
return this.$store.state[module][arg]
},
set (value) {
this.$store.dispatch(toCamelCase('update', arg), value)
}
}
return obj
}, {})
}
const toCamelCase = (...strings) => {
return strings.slice(1).reduce((camelCaseName, str) => {
return camelCaseName + str.charAt(0).toUpperCase() + str.slice(1)
}, strings[0])
}
import {createArrayActions, createArrayMutations, createLiteralActions, createLiteralMutations} from '@/store/helpers'
describe('storeHelpers', () => {
const actionsArray = createArrayActions('foo')
const actionsLiteral = createLiteralActions('foo')
const mutationsArray = createArrayMutations('foo')
const mutationsLiteral = createLiteralMutations('foo')
it('should create array actions', () => {
expect(actionsArray).to.be.an('object').that.has.all.keys('setFoo', 'addFoo', 'updateFoo', 'deleteFoo')
})
it('should create literal actions', () => {
expect(actionsLiteral).to.be.an('object').that.has.all.keys('updateFoo')
})
it('should create array mutations', () => {
expect(mutationsArray).to.be.an('object').that.has.all.keys('setFoo', 'addFoo', 'updateFoo', 'deleteFoo')
})
it('should create literal mutations', () => {
expect(mutationsLiteral).to.be.an('object').that.has.all.keys('updateFoo')
})
it('should update literal value', () => {
const state = {foo: 'foo'}
mutationsLiteral.updateFoo(state, 'bar')
expect(state.foo).to.equal('bar')
})
it('should set array values', () => {
const state = {foo: ['foo']}
mutationsArray.setFoo(state, ['bar'])
expect(state.foo).to.eql(['bar'])
})
it('should add array value', () => {
const state = {foo: ['foo']}
mutationsArray.addFoo(state, 'bar')
expect(state.foo).to.eql(['foo', 'bar'])
})
it('should update an array value', () => {
const state = {foo: ['foo', 'bar']}
mutationsArray.updateFoo(state, {index: 1, value: 'baz'})
expect(state.foo).to.eql(['foo', 'baz'])
})
it('should delete an array value', () => {
const state = {foo: ['foo']}
mutationsArray.deleteFoo(state, 0)
expect(state.foo).to.eql([])
})
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment