As far as Flux architecture implementations, Vue.js’ Vuex is one of the simplest, but most elegant. However, it still could be better. Trying to remember to write getters and mutations for every property in your store seems like a bit of unneeded cognitive overhead. And why do we need to map getters, mutations, and actions manually? What was the difference between commit
and dispatch
again? vuex-pathify
by Dave Stewart attempts to reduce all this mental overhead by supplying simple wrappers for Vuex functionality and relying on convention to reduce boilerplate.
This article assumes you have a Vue.js project with Vuex already set up, and that you know the basics of how it works. If not, take a look at our Vuex guide.
First things first, go ahead and install pathify and enable it in your base Vuex store configuration as a plugin.
$ npm install --save vuex-pathify
Then enable the plugin in your store.
import Vue from 'vue';
import Vuex from 'vuex';
// If you want to configure pathify, this import will be different.
// See the "Configuring Pathify" section below.
import pathify from 'vuex-pathify';
import App from './App.vue';
Vue.use(Vuex);
// Usual Vuex stuff. Normally not in the main file.
const state = {};
const getters = {};
const mutations = {};
const actions = {};
const actions = {};
const store = new Vuex.Store({
// Enable the vuex-pathify plugin.
plugins: [pathify.plugin],
state,
getters,
mutations,
actions,
modules,
});
new Vue({
store,
render: h => h(App)
}).$mount('#app');
So the question now is… What does vuex-pathify
do?
To illustrate this, let’s take a look at a basic Vuex setup. Just a tiny form that lets you edit your first and last name with two-way data binding.
import Vue from 'vue';
import Vuex from 'vuex';
import App from './App.vue';
Vue.use(Vuex);
const state = {
firstName: 'Richard',
lastName: 'Gator'
};
// We need these to be able to access
// their values outside of the store module.
const getters = {
firstName: state => state.firstName,
lastName: state => state.lastName
};
// We use these to update the values of the store.
const mutations = {
SET_FIRST_NAME: (state, firstName) => {
state.firstName = firstName
},
SET_LAST_NAME: (state, lastName) => {
state.lastName = lastName
}
};
const store = new Vuex.Store({
state,
getters,
mutations
});
Vue.config.productionTip = false;
new Vue({
store,
render: h => h(App)
}).$mount('#app');
<template>
<div id="app">
<h2>Your Name Is: {{firstName}} {{lastName}}</h2>
<form>
<label>
First Name
<input type="text" v-model="firstName"/>
</label>
<label>
Last Name
<input type="text" v-model="lastName"/>
</label>
</form>
</div>
</template>
<script>
export default {
name: 'app',
computed: {
// We have to create computed getters and setters for both properties
// to be able to use them in v-model.
// Quite a pain for larger forms, wouldn't you say?
firstName: {
get() { return this.$store.getters.firstName },
set(val) { this.$store.commit('SET_FIRST_NAME', val) }
},
lastName: {
get() { return this.$store.getters.lastName },
set(val) { this.$store.commit('SET_LAST_NAME', val) }
}
}
}
</script>
That’s… a lot of boilerplate for something so simple. You’ve got to create the state, add getters, mutations, and computed properties to tie them all together.
Let’s look at the same thing with vuex-pathify
.
import Vue from 'vue';
import Vuex from 'vuex';
import pathify from 'vuex-pathify';
import { make } from 'vuex-pathify';
import App from './App.vue';
Vue.use(Vuex);
const state = {
firstName: 'Richard',
lastName: 'Gator'
};
// You don't even need getters, pathify will use the store data directly!
// Though if you want, it can generate them for you with `make.getters(state)`
// Same for mutations and actions. (Uses the SET_* format, but this is configurable.)
const mutations = make.mutations(state);
const store = new Vuex.Store({
// Don't forget the plugin!
plugins: [pathify.plugin],
state,
mutations
});
Vue.config.productionTip = false;
new Vue({
store,
render: h => h(App)
}).$mount('#app');
<template>
<div id="app">
<h2>Your Name Is: {{firstName}} {{lastName}}</h2>
<form>
<label>
First Name
<input type="text" v-model="firstName"/>
</label>
<label>
Last Name
<input type="text" v-model="lastName"/>
</label>
</form>
</div>
</template>
<script>
import { sync } from 'vuex-pathify';
export default {
name: 'app',
computed: {
// The sync helper creates two-way bindings for store data and mutations.
firstName: sync('firstName'),
lastName: sync('lastName'),
// We could reduce boilerplate even further using:
// ...sync(['firstName', 'lastName'])
}
}
</script>
Looks like a significant reduction in redundant code to me!
At the center of vuex-pathify
is a path system and resolution algorithm. A path looks something like this: module/property@nested.sub.property
For example, with this path: data/user/firstName
, pathify can determine that:
user
submodule of the data
module.data/user/firstName
.data/user/SET_FIRST_NAME
.data/user/setFirstName
.If you were to pathify.get('data/user/firstName')
, pathify would first look for a getter in the user
submodule of the data
module that is firstName
. Failing that, it would directly reference the data.user.firstName
property on the store.
If you were to call pathify.set('data/user/firstName', 'Richard')
, Pathify would first check for a setFirstName
action in the relevant module. If it doesn’t exist, it would check for a SET_FIRST_NAME
mutation and use that instead.
pathify.sync('data/user/firstName')
allows you to combine both of those behaviors into a single computed property. You could use the @
syntax to access further sub-properties. For example, if you didn’t have a user
module, but did have a userData
property on the data
module, you might use pathify.sync('data/userData@firstName')
instead, to the same effect.
This allows you to access all Vuex
features with a consistent and simple syntax, instead of having to resort to commit()
, dispatch()
, and the likes.
For more details on how to use vuex-pathify
, see the official docs.
The above information should be enough to get you interested in, if not started with vuex-pathify
, but there is one thing you should be aware of. Configuring the module is done in a slightly different way than normal. Instead of using options passed to the constructor, at runtime, vuex-pathify
is configured by modifing properties on the prototype. The recommended way to configure the plugin is like so:
pathify.js
in your source directory.vuex
module.The full list of options you can modify is available here.
// Import pathify.
import pathify from 'vuex-pathify';
// Mapping: /thing -> getter: thing, mutation: SET_THING, action: setThing
options.mapping = 'standard'; // Default
// Re-export pathify.
export default pathify;
...
import pathify from './pathify'; // instead of from `vuex-pathify.
...
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
Sign up for Infrastructure as a Newsletter.
Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.
Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.