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.
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 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.
Suppose I've got comments list component with comments components. I wanna implement method that will return all comments components. I assigned to each comment component same ref:
<comments>
<comment ref="myComments" text="abc" />
<comment ref="myComments" text="efg" />
</comments>
I thought I can access all my components by this.refs.myComments but it doesn't work - it returns only last comment component.
What's the correct way to access all comment components?
There is no correct way to do that.
Your view is a representation of your data, so if you want the text for all comments, look at the data.
If you want to update the comments, update the data.
Pulling data out of the view, or manually manipulating the view defeats the purpose of react.
I currently use: Flexglobals.toplevelapplication.component1.compnent2.currentState = 'something';
is there a better way of doing do? Can I bind the state of a components to variable in my model?
Ideally, components should be self contained little pieces of your application. One component shouldn't have any effect (including changing the state) on any component, except possibly it's children.
The "Encapsulation proper" approach to change the state of an unrelated component is to dispatch an event from the component. The component's parent (or some component higher up in the hierarchy chain) is going to execute an event listener and change that state of the appropriate component, by either calling a method on the component that needs a state change or changing a property on the component that needs a state change.
If you have a complicated hierarchy, this approach can lead to a lot of tedium, creating events up the chain, and creating properties / methods down the chain in order to preserve encapsulation. Some frameworks, such as Cairngorm introduce a global singleton to avoid this tedium. In Cairngorm that singleton is the ModelLocator.
The ModeLlocator is, basically, a global dependency in your application. You can give any component access to it, and through the use of binding if a property is changed in one place, it an be automatically updated elsewhere. To change the state using binding, use an approach like this:
In the ModelLocator, create a variable to hold the state for the view in question:
[Bindable]
public var comp1State : String = 'defaultState';
In comp1 do something like this:
<mx:Container currentState="{model.comp1State}" otherComponentProperties>
<!-- other component code including defining the states -->
</mx:Container>
Then in the component where you want to change the state, do something like this:
model.comp1State = 'nextState'
Binding will take it from here. I wouldn't use his approach lightly though. It depends on the component you're trying to create and how much you car about reuse. The most common way I've seen this implemented is not with states, but with the selectedIndex in a ViewStack. But, the approach would be the same.
Yes. I usually bind the sate of my component to a property in my model.
As long as you are making the properties on your model bindable you should be able to bind
directly to you model in your view. You sitl have to set the state in you model. Id look into using a framework like [swiz][http://swizframework.org/] or or mate.