What is the correct way to call a component method in many other components in React? - meteor

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.

Related

Handling unexpected mutations properties in Vue3js

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.

redux causing component re-rendering

I have a component which is connected to global store and getting some data from the global store. from some portion of this data is sent to another component via props and inside that component i have generated required jsx based on data. Also inside the child component mapdispatchtoprops is also used and it is also connected to global store as well.
The problem case scenario is child component re-renders depends upon the global store data.
The key for global store is like -
foods : {
'list' : '',
's' : '',
fetching : 0,
slist : '',
category : '',
cproducts : ''
}
I guess what happening is the child component is re-rendered 7 times because the number of keys inside global store for foods is 7. if anyone is interested he/she can share his/her views
Components have a render method which returns the JSX markup that it renders to the DOM. For change detection, React use a local state, which is only local to a component, when the state changes the component and its children are re-rendered to update the UI of the changed state.
A quote from the React documentation:
These components must not retain internal state, do not have backing instances, and do not have the component lifecycle methods. They are pure functional transforms of their input, with zero boilerplate. However, you may still specify .propTypes and .defaultProps by setting them as properties on the function, just as you would set them on an ES6 class.
PURE COMPONENT is one of the most significant ways to optimize React applications. The usage of Pure Component gives a considerable increase in performance because it reduces the number of render operation in the application.
So change your app to be like this
import React, {PureComponent} from 'react';
class Sample extends PureComponent {
render() {
return (
<div>your structure here</div>
)
}
}
export default Sample;
Please read more on react PureComponent. here

Is it better to send redux state down to children as Props or for the Children to directly read from redux state?

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.

Meteor dynamic content without routing

What is best practice to change content on a page without creating a route?
BlazeLayout.render('mainLayout', { top: 'header', menu: 'menu', main: 'dashboard', bottom: 'footer' });
How can i hide/show template components inside the dashboard without creating a new route? Should this be done in helpers using some sort of if/else logic in the html and using helper for on button click? Let's say i want to show different content inside dashboard template based on button clicks (href).
Please provide a best practice and good solution that is easy with lots of components.
How can i hide/show template components inside the dashboard without
creating a new route? Should this be done in helpers using some sort
of if/else logic in the html and using helper for on button click?
You can do that but you should be aware of some points to keep your code clean and modular:
Try to wrap parts of your dashboard into own templates to keep the code clean
Use ReactiveDict in favor of many ReactiveVar instances
Wrap recurring parts in templates, too to reduce duplicate code
Register recurring helpers globally or in the most upper template of your Dashboard
Subscribe on the parent template to data that is shared across all parts of the dashboard and subscribe to local data in the respective components
Use autorun and subscription.ready() and display a loading indicator until the subscription is ready. Don't wait to have everything loaded before rendering as this may reduce the UX dramatically.
Let's say i want to show different content inside dashboard template
based on button clicks (href).
You can attach a data attribute to the button, that has a specific id of the target to be toggled:
<template name="dashboardComponent">
<a href class="toggleButton" data-target="targetId">My Link</a>
</template>
You can then read this id and toggle it's state in your ReactiveDict:
Template.dashboardComponent.events({
'click .toggleButton'(event, templateInstance) {
event.preventDefault();
// get the value of 'data-target'
const targetId = $(event.currentTarget).attr('data-target');
// get the current toggle state of target by targetId
const toggleState = templateInstance.state.get( targetId );
// toggle the state of target by targetId
templateInstance.state.set( targetId, !toggleState );
}
});
In your template you can then ask to render by simple if / else:
<template name="dashboardComponent">
<a href class="toggleButton" data-target="targetId">My Link</a>
{{#if visible 'targetId'}}
<div>target is visible</div>
{{/if}}
</template>
And your helper is returning the state:
Template.dashboardComponent.helpers({
visible(targetName) {
return Template.instance().state.get(targetName);
 }
});
There could be the problem of sharing the state between parent and child templates and I suggest you to avoid Session where possible. However as beginner it is a lot easier to first use Session and then work towards a more decoupled (parameterized templates) solution step by step.
Please provide a best practice and good solution that is easy with
lots of components.
This is a high demand and it is your competency to work towards both! However here is a short peek into this:
Best practice is what works for you plus can work for others in other use cases. Try to share your work with others to see where it will fail for their use case.
Using routes has the advantage, that you can use query parameters to save the current view state in the url. That adds the advantage, that on reloading the page or sharing via link, the page state can be fully restored.
easy with lots of components is a contradiction and I don't know if you expect some magical puff that solves this complexity for you. As a software engineer it is your competency to abstract the complexity into smaller pieces until you can solve the problem within certain boundaries.

Data model in child component

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.

Resources