Is it a good idea to pass whole object to child component? - vue.js

It's a question about performance
I have a big object with a huge amount of fields (and maybe with a nested objects too).
I have a page component, it receives this object from server.
I have some child-components inside page component. One component needs a several fields from the object, should i pass them as a single prop for every field, or i can pass a whole object? Is it affects to performance?

Related

VueJS - Update a parent computed property after a child component modifies prop data

I have a relatively complex API request object I need to make, with a large number of UI components responsible for updating different properties of the object.
I'm passing the basic request model as a prop from a parent component to its children, which pass it on to theirs (down several "generations").
At the parent level, I have a computed property that returns a field of this data model, and a watch on that computed property.
When a child component updates the property on the model, it successfully updates everywhere that has a reference to it, but the computed property on the parent fails to recalculate, and resultantly the watch never activates.
I'm guessing I've missed the point somewhere along here, but I can't think about how else to update without resorting to long event chains through the UI.. How should I be approaching this instead?
To anyone with a similar question - from my research it seems that modifying reference values on props is not the intended approach for VueJS. Which is a shame, because initially it seemed like quite a neat pattern.
I've implemented vuex now, which is working well, and avoids long lines of events going back to the original owner of the prop data.
IF you wanted to press it, then modifying references on the object itself will force updates down the chain. So (e.g.) if you wanted to update an array property of the prop data, then instead of "pushing" to it, you would replace the whole array object (causing other components with computed properties on that array property to recalculate). But again, not recommended.

Can a Parent and Child listen to same event and merge data together - Vue?

If I have a button in the parent class, and a child class stores certain data. The parent class also stores different data.
When we click on the parent's button, is it possible for the child class to listen to this event and then pass this data into the parent, then the parent also grabs its own data and merge this data together?
How can they both listen to the same button event, and then retrieve data and pass data to one another? The data needs to be passed through another function to format/change the values too, not just displaying this data.
Is this possible and how, since this button seems to affect two components and data is passed along?
Thanks!
Children cannot catch parents' events. Children can expose methods that parents can call, or you can create a reactive property that represents whatever state changes when the parent button is clicked.
Events are messy and low level and you shouldn't mourn not being able to use them. Using state and reactivity is much cleaner. Vue components should really only store "private" state. Props are available for passing state down to immediate children. It's much better to extract state into a) a plain old javascript object, passed around via data or provide/inject, or b) vuex, then watch reactivity work its magic.
When you define your data, you can reference anything anywhere. So if you create an object in global scope, let's call it $myState...
Vue.prototype.$myState = { myProp: "hello", myName: "Simon"}
then you can reference it in your data in any component...
data : function(){return { myState : this.$myState }
Some people will object that doing this creates spaghetti - anything anywhere can modify your global state object, but for many many applications, the simplicity gained by "normalizing" state and storing it centrally will outweigh the costs.

Pass entire data item vs just id as Prop in Vue list when using VueX

I have a VueX state that contains a list of items. E.g.:
{
operations: Operation[]
}
We need to display each Operation as an item in a list. So we have an OperationList component and an OperationItem component.
When it comes to rendering the list (v-for), would it be recommended to pass the entire item as a prop or just the id and have the OperationItem read the data from VueX?
Basically:
<operation-item v-for="operationId in operationIds" :id="operationId" :key="operationId"/>
vs
<operation-item v-for="operation in operations" :operation="operation" :key="operation.id"/>
I think it might be a preference choice but in my projects I usually pass all the prop of the components that way :
<operation-item
v-for="operation in operations"
:key="operation.id"
:prop1="operation.prop1"
:prop2="operation.prop2"
:prop3="operation.prop3"
/>
I'm not sure if that's a good practice or not but in this case, it's more flexible, you don't need to give a structured object for it to render, you just have to give it all it's properties.
A bit like for a class constructor, I would pass all the necessary parameters separately instead of passing them in an $option array or Settings class.
For some components, it also doesn't make sense for them to be aware of the store, they should juste be "stupid" rendered components.
I hope it's clear enough that you get my point !
I'd say pass the entire item. That way your component doesn't need to know where the data came from and you would be able to reuse the component in situations where the data didn't come from Vuex.

Vue.js 2.0 - creating reusable components

I am trying to create fully reusable component using Vue.js 2 and single file components, and right now my approach seems to be impossible to realize.
The goal is to create component for creating forms for a complex, nested JSON structure. This structure is supposed to be edited and then sent to the server. The component itself displays a header and submit button but the fields along with their placing is entirely the responsibility of the user of my component. (front-end engineer)
The MyForm component (implementation is not relevant here) is passed the JSON data and url to post them to.
The form is supposed to be reusable by many other users and the contents of the form itself is supposed to be not relevant. It may have a mix of html/inputs/custom components as children.
Let's imagine a simple scenario without data nesting with the following data:
var mymodel={ name : "My name", surname : "My surname" }
And a form i would like to create using my component:
<MyForm :model="mymodel" :url="http://localhost/post">
<div>
<MyTextInput v-model="model.name" label="Name"/>
<MyPanel>
<MyTextInput v-model="model.surname" label="Surname"/>
</MyPanel>
</div>
</MyForm>
Therefore:
MyForm gets passed a model to submit, stores it in data
MyTextInput is a custom component for displaying input with label
Second MyTextInput is the same component but created in another component contained called 'MyPanel' since this field needs to be placed differently.
As we can see there are many problems with passing variables and composition itself:
Composition:
If i put a <slot></slot> in the tempplate of MyForm for displaying the fields it would be compiled in parent scope, therefore all children (including MyTextField) would not have access to the "model"
If i try to use <MyForm inline-template> i cannot automatically display the form header and footer since all content is being replaced. Additionally when using single file components the compiler will look for all components inside the inline-template which means that i would have to import MyTextInput and MyPanel into MyForm which is not practical. I do not know in advance all components that will never end up in my form!
Passing variables:
If i use the variables directly from "model" (in first TextInput) i receive warning that i am modifying a variable from parent and it will be overwritten on next render (but in this case it will not be overwritten since i am INTENTIONALLY modifying the parent)
I cannot pass the model into second MyTextInput without passing it to MyPanel first. Actually i would have to pass it into EVERY custom component in between. And i do not know in advance how many custom components will there be. Which means that i would have to modify the code of every component that would ever be put into MyForm and require users to pass the data for each custom component they include.
If i would try to properly inform the parent about changes i would need to add v-on: event to every textinput and every custom component in between in order for the event to reach MyForm.
As i have said the component was supposed to be simple and easilly reusable. Requiring users of this component to modify code of every child they put into it and requiring them to add v-on: to every component inside does not seem practical.
Is my idea solvable using Vue.js 2.0 ? I have designed the same component before for AngularJS (1.5) and it was working fine and did not require to add modifications to each child of the form.
I've been using a ui framework based on vue 2.0 and you may get some ideas from its implementation. Based on its implementaion and my little experience with it, I think it's the person who uses your framework's responsibility to assemble the form-model. Also, for a form, we can always easily get all the data to be sent by using fields' value props without v-model's help.
The framework's doc on form element may also be helpful but it's currently only available in Chinese except for the code samples.
I suggest you to use Form Input Components using Custom Events to pass variables in your form.
Mutating a prop locally is now considered an anti-pattern, e.g.
declaring a prop a and then set this.a = someOtherValue in the
component. Due to the new rendering mechanism, whenever the parent
component re-renders, the child component's local changes will be
overwritten. In general, in 2.0 you should treat props as immutable.
Most use cases of mutating a prop can be replaced by either a data
property or a computed property.

Children to children communication

My component is pretty big so I will give you simplified example, maybe someone will know how to solve my problem.
I have invoice component with children components like 'subtotal', 'vat_subtotal', 'total' (it's example). I'm using v-ref to get direct access to every child from invoice component. Also, subtotal is calculated from invoice properties, then vat_subtotal is calculated from subtotal children properties. And 'total' is calculated from vat_subtotal children.
Example:
invoice.$refs.subtotal.total = {some calculations}
vat_subtotal.total = #$parent.$refs.subtotal.total * 1.21
total.total = #$parent.$refs.vat_subtotal.total
The problem is that i'm getting warnings when page loads, be cause 'total' children is trying to access 'vat_total' children properties, but #$parent.$refs.vat_total is still 'undefined' (I don't know why. When later im changing something in form, it reacts normaly and recalculate everything right). It seems, that one children is trying to compute properties while other children isn't loaded yet.
Don't reach into a child for data. If the parent needs access (in your case, to give access to another child), the data item should be created in the parent and passed as a prop to the child. That is how data can be shared among multiple children. Child components should not depend on other child components being available through the parent (or on anything in the parent, really, if it isn't passed in as a prop).
If the child component is responsible for changing the prop value, you can pass it using .sync.
The way you are trying to solve things is technically possible but highly discouraged. As stated in the docs:
Although it’s possible to access any instance in the parent chain, you should avoid directly relying on parent data in a child component and prefer passing data down explicitly using props. In addition, it is a very bad idea to mutate parent state from a child component, because:
It makes the parent and child tightly coupled;
It makes the parent state much harder to reason about when looking at it alone, because its state may be modified by any child! Ideally, only a component itself should be allowed to modify its own state.
In general, you should aim for creating a model representing the state of your application. Instead of accessing parents / children directly, pass any relevant data down to children using props. Children can notify their parent about changes using events, or you can use .sync binding to synchronize models automatically.
I think that you would benefit from reading about more structured approach to Vue application architecture. I'd start with Flux-inspired Application Architecture for Vue.js.