If I have 2 Lit elements, with a parent-child relationship, e.g.:
<x-parent>
<x-child></x-child>
</x-parent>
Are the connectedCallback calls executed in a deterministic order?
In my tests looks like the connectedCallback for the parent is always called first, but I don't know if I can rely on this being always the case.
UPDATE AFTER #justin-fagnani answer
#justin-fagnani Not sure if we are talking about the same, you wrote about when the component is defined, but my question is about the order of the connectedCallback. Anyways, based on your answer, I think that the child callback happens first if it is rendered using a <slot>:
render() {
return html`<slot></slot>`;
}
lit playground example 1,
But parent callback happens first if the child is rendered with a lit-html template:
render() {
return html`<x-child></x-child>`;
}
lit playground example 2
Is my assumption correct?
connectedCallback: Is Invoked each time the custom element is appended into a document-connected element. This will happen each time the node is moved, and may happen before the element's contents have been fully parsed.
This is equivalent to ngOnInit (Angular) and componentDidMount (react) lifecycles,
So yes parent method will be invoked first.
Ref: Link to mdn docs
The exact order depends on a few things around element definitions and upgrades.
<x-parent>
<x-child></x-child>
</x-parent>
For this snippet, if both <x-parent> and <x-child> are defined before the HTML is created, then yes, the order will be [<x-parent>, <x-child>].
If the HTML is created first, then the order will be the order in which the components are defined.
First, let's assume that the component definitions are in separate modules and don't import each other.
Here the parent will be defined first:
<x-parent>
<x-child></x-child>
</x-parent>
<script type=module>
import './parent.js';
import './child.js';
</script>
Here the child will be defined first:
<x-parent>
<x-child></x-child>
</x-parent>
<script type=module>
import './child.js';
import './parent.js';
</script>
If one of the component definitions imports the other, then the depth-first first imported component will go first:
Here the child will be defined first:
parent.js:
import './child.js';
HTML:
<x-parent>
<x-child></x-child>
</x-parent>
<script type=module>
import './parent.js';
</script>
So if you want a guarantee on which will be defined first in all cases, have the every component import the ones that need to be defined first.
Related
I have a vue3 webapp that I use to edit some multi-pages documents.
All the pages are stored in a state with pinia. My pinia state is an object with a pages property that is an array containing all the data of each page.
Each page of each document use a specific template, so I created multiple components to handle each template, and I also have subcomponents for some parts that can be found across multiple templates.
I loop through the pages with a root component, passing a reference to the page object, like it :
<PageWrapper v-for="page in pages" :key="page.id" :page="page" />
Then, inside the PageWrapper component, I use the according page template's component, passing along a reference to the page object (the same with subcomponents if any) :
<PageFirst v-if="props.page.type === 'first'" :page="props.page" />
<PageServices v-if="props.page.type === 'services'" :page="props.page" />
<PageTotal v-if="props.page.type === 'total'" :page="props.page" />
<PageContent v-if="props.page.type === 'content'" :page="props.page" />
I wonder what would be the best way to edit a property of my page object from a subcomponent, as I know that it is a bad practice to mutate the property directly.
Do I have to use events ? Is PageWrapper the good place to catch all the events and the modifications?
Any advice on this matter would be of great help to me.
Thanks a lot for your help!
As the Vue official document point out:
In most cases, the child should emit an event to let the parent perform the mutation.
So the answer is you should let the parent do the job of mutating the props. And it will never be a bad solution.
But, look at your design. Your parent component PageWrapper works just like a wrapper. It does nothing but a container for its child.
The props one-way data flow prevents child components from accidentally mutating the parent's state, which can make your app's data flow harder to understand. But if the parent does not actually handle state and your child component's data does not relate with each other, mutating the props inside the child component will be fine.
I realize this is a fundamental question that may have been answered before, but I'm looking for a definitive answer, with perhaps some reasoning, as I've not quite found one that convinces me that there is better/best/preferred way to do handle this.
Scenario: A dashboard component receives redux state via connect. Some of the data is shared across the dashboard and its children. Some of the data is specific to the dashboard's children.
Question: Should I always pass the props down to the child components (something) like the below, or should I always connect the child components to redux and read the needed data directly from redux state?
import React, { Component } from "react";
import { connect } from "react-redux";
import ChildOne from ".ChildOne";
import ChildTwo from ".ChildTwo";
class DashboardExample extends Component {
render() {
const { sharedData, childOneData, childTwoData } = this.props
return (
<div>
<h1>{sharedData.selectedDate}</h1>
<ChildOne sharedData={sharedData} childOneData={childOneData} />
<ChildTwo sharedData={sharedData} childTwoData={childTwoData} />
</div>
);
}
}
const mapStateToProps = state => ({
sharedData: state.dashboardData,
childOneData: state.childOneSpecificData,
childTwoData: state.childTwoSpecificData,
});
export default connect(mapStateToProps)(DashboardExample);
As Dan Abramov said, it’s nice to have a division between Presentational Components and Container Components.
Presentational Components
Are concerned with how things look.
May contain both presentational and container components** inside,
and usually have some DOM markup and styles of their own.
Often allow containment via this.props.children.
Have no dependencies on the rest of the app, such as redux actions
or stores.
Don’t specify how the data is loaded or mutated.
Receive data and callbacks exclusively via props.
Rarely have their own state (when they do, it’s UI state rather than
data).
Are written as functional components unless they need state,
lifecycle hooks, or performance optimizations.
Container Components
Are concerned with how things work.
May contain both presentational and container components** inside but usually don’t have any DOM markup of their own except for some wrapping divs, and never have any styles.
Provide the data and behavior to presentational or other container components.
Call redux actions and provide these as callbacks to the presentational components.
Are often stateful, as they tend to serve as data sources.
Are usually generated using higher order components such as connect() from React Redux, createContainer() from Relay, or Container.create() from Flux Utils, rather than written by hand.
source post
————————————
Specific answer to your question:
I find it helpful to try and stick with the principles stated above. It makes your code easy to reason about and it helps to separate concerns (Views / Business logic).
But, if you find yourself writing spaguetti props to stick to it, or if it doesn’t feel natural in a specific piece of code, just connect your Presentational Component.
I have a custom component with an input property as follows:
export class MyComponent{
#Input() value:number;
}
So that I can plop one on a parent component:
<my-component [(value)]="someValueAtParentComponent"></my-component>
Note that I did not provide #Component decorator and the class for the parent component because I don't think those are relevant.
Now, things happen internally in MyComponent that can change the value of value.
From inside MyComponent's template, I display {{value}}, and it displays the correct value throughout its lifetime.
From the parent component's template, I display {{someValueAtParentComponent}}, but it doesn't update with MyComponent's value. I thought [(value)] will automatically do the job, but I guess not.
I don't want to create an #Output event on MyComponent for the parent component to handle the event where it would set someValueAtParentComponent explicitly.
I believe Angular wants to emit an event for a parent component to handle, but that seems very tedious. Is there something we can do in our own components so that we may use the syntactic sugar [(value)] instead of [value]="..." (onValueChanged)="onValueChangedHandler($event)"?
I am using React with Meteor. I am currently building an app that has grown to have a sizeable number of components (some nesting quite deeply, like 5 or more levels).
I often find myself having to pass props from the parent all the way to the children, just to call a component method for a component that has been rendered in the topmost parent, like this:
Parent File
openDialog() {
this.setState({ open: true });
}
render() {
return (
<div>
<Dialog open={ this.state.open } />
<ChildComponent openDialog={ this.openDialog.bind(this) } />
</div>
);
}
ChildComponent
render() {
return (
<div>
<GrandChildComponent openDialog={ this.props.openDialog } />
</div>
);
}
And so on, just to call the openDialog method defined right at the topmost parent.
This works if you only have one branch going deeper inwards. However if you have say, a login modal dialog which can be triggered from many different parts of a site (header, sidebar, inline links, etc), it is obviously impractical to pass in props this way into every single component which could possibly require the link (or not).
What is the correct (recommended) way to handle this kind of issue?
The common solution is to link your component to an external set of actions and an external State Manager. Flux architecure is used for that. And several frameworks, like Redux, help you integrate it with React.
With flux, you can dispatch an action (openDialog for example) from every component without having to pass it through the whole tree of components.
I would like to know what the best practice is for a communication between parent/child components. I have read this blogpost about communication and components states but haven't found the right answer for my problem.
Following components are considered.
My parent component is a List, which renders several Tasks (child component) from objects in the parent component.
So my questions are:
Is it best practice to pass the object to each Task component?
When a value has changed in the Task component, how does the parent component know about this? Because the parent should know about the infos of all children.
So is this a right pattern to use?
In my Parent Component I have this in the render function:
<Task key={index} taskdata={taskobj} />
My Task child component looks like this:
render() {
return (
<input type="text" name="wunsch" defaultValue={this.props.task.title}/>
);
}
So if the value of the input field will change, does taskobj in the parent component also change? In this example no. But what would be the right pattern here?
Basically when you want to pass information from parent to children you use props, when you want to pass information from child to parent you pass a function to a child as a prop and then call it when you need to update a parent.
You can read more in official docs
Also you can take a look Reflux.
A simple library for unidirectional dataflow architecture inspired by ReactJS Flux
In React, data flows one way
I wasn't really aware of this React concept.
So after reading this link in the ReactJS Doc I decided to the onChange/setState() way as ReactLink is already deprecated.
So when a change in the model happens in the child component I call a method in the parents component to update (setState) my data.