Vuex best practices for complex objects - vuex

My Vuex store contains objects with a variety of complexity. Some have nested objects, some have arrays of nest objects.
I could create generic function to mutate a specified property along the lines of:
setProperty(state,{ type, id, prop, value })
{
state[type][id][prop] = value;
}
but that will quickly get complicated for nested object, arrays of objects. It also seems very tedious to have to create a mutation for every single object property, nested or otherwise.
What are the best practices for creating mutations to modify objects, nested objects, arrays, etc?
Another related issue, is it considered bad form to pass the objects into the mutations as opposed to looking them up in the state:
setProperty(state,{ obj, prop, value })
{
obj[prop] = value;
}

Generally speaking, it is best if you just could avoid nested state structure at first place. I'm not sure how your data are structured, but if you're doing that because you have relationship between those object or area of object, it might be worth trying normalizing the state shape.
Here is the good article from Redux author. It's talking about Redux but the core concept is very same for the Vuex.
https://redux.js.org/docs/recipes/reducers/NormalizingStateShape.html
And the Vues ORM is a library that do that for you automatically.

Related

Is it standard to copy collections out of vuex state to prevent mutation?

I’ve scoured the vue forum and there’s a lot of answers that are 2 years old and close, but I’m having a hard time getting one specifically addressing this (I’m simplifying the example):
I have an array of objects in state (row data for a table)
And a tableComponent with subComponents which for-loops through the data and creates one row per item in the collection
The requirement is to add an input to each row in the table which is bound to rowData.foo
The tableComponent has a computed property that gets rowData from state, puts those objects into a new (modified) array, and passes it into the tableComponent template
Which then adds the input with a v-model of rowData.foo
This works, but I recently realized that it is modifying the foo property of a rowData item in the collection without committing a mutation.
I’m ok with dropping v-model and using #input to commit the change, but I have two questions about how this should work
If I want to block these changes until I hit a “confirm changes” button, is it standard / performant to
_.cloneDeep the whole collection in either the tableComponent computed property or in the vuex getter. It seems like a lot of overhead but maybe I’m being too conservative about that?
Allowing v-model to update RowData.foo directly means each row knows which RowData item to modify, now that I’m committing a change to a single object in a vuex collection, is the best practice to make the vuex mutation _.find the object, change it, and then spread the whole collection back into the store?
As with most of my other vue questions, I have multiple ways that make it work, but I’m not sure what the most performant/best pattern is. Thanks for any help!
Update
Simple codeSandbox here: https://codesandbox.io/embed/vuex-store-olrvk
See how the vuex data is updated without an action call?
After reviewing your codeSandbox sample i found that YES your store state data rowCollection is getting mutated without using any mutation and that's because of the v-model (two-way binding) that detects the data spot in memory and mutates it behind the scenes ... of course this was allowed by Vue devs even tough i couldn't find about this at any document (and by the way on the doc they showed an example of a state mutation using v-model but they used a store mutation for that )
and concerning what is the most performant/best pattern i think this way is the easiest and much cleaner (less code)
If you need to buffer user changes to a reactive model (for a commit operation), you will need to make a deep copy. There is no way around it. Totally normal.

Vue - use vuex instead of eventbus for calculations with nested data & components

I have app when bind big JSON object into component, then some parts from this object into next components etc. - it's structure with many deep levels, but object is not copied, I use advantage that objects are passing by reference.
Components on the lowest level have fields like "price", "qty" etc. When user modifies them, I updated object and run recalculation using global eventbus - after recalculation is done, I also use eventbus to forceUpdate some components. For example parents of these with fields price/qt, to refresh "total" amounts in categories.
Now I move some code to vuex and consider also here. Think that recalculation after commit will be ok. The question is - how can I modify this big object using commit from children components? The problem is that commit must "know" what part of object has been modified (for example, one element inside one of many categories)... I can do it in other way, pass child and parent data in commit and update parent but... will it work? I also need reference to do this in proper way...
Maybe still use binding to pass elements, but call store action to only make recalculation (not sure, that provides automatic refreshes on all required modules).
Or maybe other, better solution?
I think you have some problems with architecture. Main idea here is to have some container (smart) component, that is connedcted with store (vuex), and simple (stupid) components, that recieve data from props. Also you must divide your store into modules, so it'll be easy to maintain. This approach will allows you to modify exactly pieces of data you want.

Vue watchers and components

Vue newbie here - we are introducing Vue into an existing application bit by bit and therefore I am slightly constricted by this with regards to the back end. The Vue template gets an array of objects from the Django backend. Some of the objects returned are parents and others are children of the parents - identified by the parent_id.
These are rendered happily using various components to encapsulate some of the functionality.
The update end point for the back end is configured to take one single object and update the database accordingly, therefore the watcher must be able to identify which of the array of objects has been updated. From my understanding this isn’t possible for objects/arrays in Vue/Js as the before/after values aren’t available for anything other than simple types.
The workaround I have put in place is to clone the array of objects in a computed property, and then compare the new array to the computed array to identify which object has been modified in order to send that back to the back end.
Is this best practice, or am I going to fall foul to this decision later on down the line?
many thanks for your help
It would be better if you give the objects of the array their own components, so you have a vue component that takes as a prop the object and you then use a v-for on the array to create one instance of the "object component" for each object in the array.
Then you can have a watcher on the object prop in the object component and you will know exactly which object has changed and get better control.

shoud I use vuex getters even when no computation is involved?

If i just want to return a member of my vuex state, should I define a getter for it? or is it o.k. to use mapState ?
My dilemma is as follows:
1) It seems redundent to have a getter that simply returns a member of the state as in:
getters: {
user (state) {
return state.user
}
}
when I can just use the following code in the consuming component and save the coding of the getter ?
computed: {
...mapState('auth',['user']),
}
However, if something did change in the future and I would like some computation done on the user object before it is returned then using a getter and
computed: {
...mapGetters('auth',['user']),
}
Would allow for a simpler change.
But if this is the recommended way to go then why provide mapState to begin with?
So should I use getters for this type of simple state memeber access? or not?
Technically, as you note, you can do either way. When there's no calculation involved, though, it becomes a matter of taste.
There's no authority in this, but I'd recommend as general advice:
If your application...
has a stablished state format AND
your state that doesn't tend to change AND
your application is not that big,
...then map to state.
Else, use getters.
In other words, if your application is somewhat small and should be stable, then, why not?
If else, other than the obvious "use getters when you need calculations", if your application:
tends to grow OR
has a state structure that is not stablished and tends to change OR
has deeply nested state.
Then use getters. They decouple you application from the state, allowing it to change more freely (which is frequently
needed "in times of trouble"), simplifying refactoring a lot.
In other words,
when in doubt, use getters instead of mapping directly to state.
Note: IMO, this question is the same as using Selectors in Redux. And, in Redux, the usage of selectors is widely recommended.

MVC / Observer & Immutable Data Structures

Can You please explain what are analogues of MVC / Observer techniques in two cases:
Immutable Objects (OOP style)
Immutable Data (functional style)
For example let's consider following simple GUI example (You can try it live here http://tinkerbin.com/0XDHRXIl click 'Run' button to start it and wait 2 sec for text to appear)
It's built with JavaScript because it's easy to play and MVC / Observer are very natural to it
// Model containing the data.
var Post = Backbone.Model.extend({})
var PostView = Backbone.View.extend({
initialize: function() {
// Registering view rendering method as
// an observer on the model.
this.model.on('all', this.render.bind(this))
},
// Every time state of model changes
// this method will be called.
render: function() {
// Printing value of model.text attriubute.
this.$el.html(this.model.get('text'))
return this
}
})
// Now, any time the model is updated the view will be also
// automatically updated.
post.set({text: "hello, it's me"})
But I don't quite understand how to do the same with Immutable OOP and Functional styles, what ways are there?
In case of classical MVC and OOP techniques there are implicit identifier for every object - its reference. Observer relies on this reference/identifier to dispatch messages to correct objects.
In Immutable world reference doesn't identify object anymore (there may be multiple references for different versions of object) and in functional world there's no objects at all. So, we need to explicitly supply the object identity.
The analogue of Observer in Immutable/Functional world is a Pub/Sub with explicitly provided object IDs.
Regarding an immutable OOP style I would suggest to apply the following modifications: Instead of "changing the model state" you would have to create a new model state each time there is a state change. Instead of pulling the state in the observing function in the view, I would pass the immutable state as parameter to the observe function (here: the render function).
As inspiration for a more functional approach to the observer design pattern, you might want to have a look at reactive functional programming. Particularly, I would recommend the somewhat controversial paper on Deprecating the Observer Pattern.