In my project, I need to know the changes in the child components in real time from the parent component.
So I'm going to use watch in a child component to emit event to the parent component whenever the data in the child component changes.
Is this a bad way? I'm afraid there's an unnecessary overload in this flow.
If you have a better way, please recommend it.
There's nothing wrong with this approach. Vue is very efficient in the way it detects changes, and there shouldn't be an unnecessary overload, unless you watch more than you need to. You shouldn't notice any performance issues unless you have a huge object graph (eg thousands of objects being watched).
Make sure you only watch the properties that require change detection, and only use deep:true if you really need to.
Related
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.
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.
I have built a complex date management component that itself is made up of many smaller components nested a few layers deep. The components at different levels need access to observables and actions that live in the root component. I am dealing with this by passing what I need through props. While this all works, the code would be much simpler and easier to follow if I could create a store in the root component, use provider, and then inject in the child components as needed. Exactly like we do when creating a store for app wide use.
So to summarize...
I want each instance of my complex date component to create it's own instance of a store. I want to then use provider and inject to pass this store instance to child components.
Before I proceed with this significant refactoring, I want to be sure that this approach will work and is sound. Is there an alternative approach that makes more sense. Am I overlooking something?
Note: Although I know code samples are useful, I'm hoping that what I am describing is straight forward enough that they are not needed in this case.
Yes, you can create stores for a component and use Provider and inject to pass them to child components. Actually that is what I do in my current project and it works well.
BTW, I think this is a big Pro of MobX compared to Redux. You do not need to keep all states in a single global store. You can create complicated components that work perfectly by themselves. It is object-oriented, which is the philosophy of React.
Is there any other way to pass data between 2 siblings without using event bus or parent component in vue js?
I know that it can be passed with the help of Props and event emission. It can also be passed with the help of event buses.
If it is complex you would go you Vuex is the best solution in my opinion. However, if you just want a simple way to communicate between the components, you can simply go for OO Shared State. This is just a class that maintain your data that you can access from any components just pass it though, similar to singleton concept it OOP. There is a good example how to do this in Laracast website; have a look here https://laracasts.com/series/learn-vue-2-step-by-step/episodes/24.
A general question is going to get a general answer. You need to ask yourself why your siblings need to talk to each other. Most often it's because you're not using a store. It would be a mistake to think of vue components like objects in an OO language. Vue components are fed via reactive pipes from a store, the store is not a vue component. If you're doing this correctly, you don't often need to pass stuff between vue components.
Is there a way to force a managed object into the dirty state? I have a managed object that has a relationship to a parent managed object. If I change a property on the child managed object, I was curious if there is a way to put the parent managed object into a dirty state.
On Mac, you should use NSPersistentDocument for most cases where this would be useful.
On iOS 5+, you should use UIDocument.
If these aren't possible, then you can either have the parent observe changes in its children, or have children set a changed flag on their parent. In either case, you can modify some "last changed" property to cause yourself to become dirty.
You can also create a method like -hasChangedChildren that would walk the children tree and return YES if any are dirty. This has the advantage of not actually modifying the object, so you don't impact any Core Data optimizations. The docs do not forbid modifying hasChanges to behave this way, but I would personally be careful doing so.
But if at all possible, you should use the document classes, since this is what they're for.
You may also be interested in Core Data Questions--Relationships, UUIDs, and Dirty States.