Vuex is great for the right application but since it imposes a lot of limitations on how you can change data in your store, it may not be ideal for simpler use cases.
Vue Observable introduced in Vue v2.6.0 could be a lightweight alternative to statement management in smaller applications. I recently used it in a way similar to Vuex ie. reference a state property using getters and manipulate the state using mutations without actually accessing the store directly.
So lets create a store with an object users
:
(Sorry about the contrived example, I'm writing for the first time so couldn't think of anything better.)
import Vue from "vue";
const state = Vue.observable({
users: {
c6676a9aca4c270086ef31a35cc80446: {
name: "Ibrahim Ezzy",
twitter: "3zzy",
bio: "Software Imagineer. Front-end, UI & Design."
},
"4d50982553c3286d65182075c178245f": {
name: "Tim Apple",
twitter: "tim_cook",
bio: "Chief Executive Officer of Apple"
}
}
});
A generic setState
method to update any object within the state:
const mutations = {
setState({ object, objectPath, value, upsert = false } = {}) {
console.log("setState args: ", { object, objectPath, value, upsert });
if (state[object] === undefined || value === undefined)
console.error("setState: Invalid Object or Value");
if (objectPath === undefined) state[object] = value;
if (objectPath && Array.isArray(objectPath) && objectPath.length) {
let navigate = [object, ...objectPath.slice(0, -1)],
valueObj = navigate.reduce((obj, prop) => {
if (typeof obj[prop] !== "object") {
if (upsert) {
obj[prop] = {};
} else {
console.error(`setState: property '${prop}' doesn't exist`);
}
}
return obj[prop];
}, state);
Vue.set(valueObj, objectPath[objectPath.length - 1], value);
}
}
// other specific mutations ...
};
And a generic getState
method to get any object from the state:
const getters = {
getState({ object, objectPath } = {}) {
if (state[object] === undefined) console.error("getState: Invalid Object.");
if (objectPath === undefined) return state[object];
if (objectPath && Array.isArray(objectPath) && objectPath.length) {
let navigate = [object, ...objectPath.slice(0, -1)],
valueObj = navigate.reduce((obj, prop) => {
if (obj[prop] === undefined) {
console.error(`getState: property '${prop}' doesn't exist`);
}
return obj[prop];
}, state),
value = valueObj[objectPath[objectPath.length - 1]];
if (value === undefined) console.error(`getState: Invalid object path`);
return value;
}
}
// other specific getters ...
};
Now you can access the users
like so:
data() {
return {
users: getters.getState({
object: "users"
})
};
}
and update (or create) using setState
:
methods: {
updateName(e, id) {
console.log(e.target.innerText, id);
mutations.setState({
object: "users",
objectPath: [id, "name"],
value: e.target.innerText
});
}
}
Probably the most interesting part here are the dynamic getState
and setState
methods that can create, update, or access deeply nested properties within the state. Of course these functions aren't perfect and they just work with Objects
for now, but you get the idea.
Here's a demo on CodeSandbox.
Top comments (4)
With the amount of code you have to write for the
getState
andsetState
methods, it seems like a simple Vuex store would work better, no? With Vuex you could just setup your state with whatever data you want to "observe" and then you can just change it directly through a mutation, which also would enforce not touching the state directly from your component.Based on the small documenation for Vue.observable, it seems like you would use it when you want to modify state directly and make sure your application is reactive to that change, which would make more sense for small projects that wouldn't need to use Vuex.
Super cool! Btw I think it would be easier to read if you used syntax highlighting on your code snippets.
Long long ago there is a main stream Vuex alternative: Vue mixin (compatible with Vue 1.x & 2.x).
For more info: github.com/kenberkeley/vue-state-m...
You may should turn it on a small lib... and share with us;