How does one React component call a method in another React component? - reactjs

My page contains two completely separate React components (different files, different classes, no parent-child relationship).
How can one component call an instance method in another component? The problem seems to be obtaining the instance of the target component.
EDIT: Both components share the same parent (i.e. they are rendered in the same render() method) but I still don't know how to pass the reference of the target component to the calling component.

The short answer is: they don't.
It's not clear what you're trying to accomplish, so I can't speak to the specifics of your case, but the way React components "communicate" with one another is via state and props. For example, consider a Page component that has two child components, CompA and CompB, rendered something like this:
<Page>
<CompA />
<CompB />
</Page>
If CompA needs to pass something to CompB, this is done through state on the Page component, with that state exposed as props on CompA and CompB, something like this:
class Page extends React.Component {
constructor(props) {
super(props);
this.state = {
sharedValue: 42,
};
}
onChangeSharedValue(newValue) {
this.setState({ sharedValue: newValue });
}
render() {
return (
<div>
<CompA
sharedValue={this.state.sharedValue}
onChange={this.onChangeSharedValue}
/>
<CompB
sharedValue={this.state.sharedValue}
onChange={this.onChangeSharedValue}
/>
</div>
);
}
}
If CompA needs to change the shared value, it calls the onChange handler, which will change the state on the Page component. That value will then be propagated down to the CompB component.
There is no direct communication between components like you're describing; it is all done via state and props.

"Props down, Events up."
If you provide us a specific example of what you're looking for, I can update this post with a more specific response.
But in general, there are a couple of strategies that you can take. Some of them are presented here.
The preferred approach is to simply move your calling method to the parent component. It's a common strategy in React.
If you're not able to, then the next step would be to write an event handler for the parent, and then pass this event down to the first child component.
Use this event to pass information up to the parent, so that when it gets triggered, data can be passed as props down to the second component.

I only recently started doing React development and I found a solution for this problem that suits me. Admittedly, I haven't seen it referenced anywhere and when I showed it to a colleague who's been doing React for years, he kinda furrowed his brow and felt that it wasn't "right", but he couldn't really articulate to me why it's "wrong". I'm sure I'll be shouted down for it here, but I thought I'd share anyway:
File #1: objects.js
let objects= {};
export default objects;
File #2: firstComponent.js
import React from 'react';
import objects from 'objects';
class FirstComponent extends React.Component {
constructor(props) {
super(props);
objects['FirstComponent'] = this; // store a reference to this component in 'objects'
}
doSomethingInFirstComponent() {
console.log('did something in first component');
}
render() {
return (<div></div>);
}
}
export default FirstComponent;
File #3: secondComponent.js
import React from 'react';
import objects from 'objects';
class SecondComponent extends React.Component {
render() {
objects.FirstComponent.doSomethingInFirstComponent(); // call the method on the component referred to in 'objects'
return (<div></div>);
}
}
export default SecondComponent ;
When SecondComponent renders, it will trigger the console.log() in FirstComponent.doSomethingInFirstComponent(). This assumes, of course, that FirstComponent is actually mounted.
The "React Guys" that I know seem to think this approach is somehow evil. It uses a simple JavaScript object outside the normal React scope to maintain a reference to any existing objects that I choose to store there. Other than them telling me that "this isn't the way you do things in React", I haven't yet found a good explanation for how this will break or otherwise screw-up my app. I use it as a low-grade replacement for massive-overkill state-management tools like Redux. I also use it to avoid having to pass properties down through dozens of layers of React components just so something at the last level can trigger something waaaaay up in the first level.
That's not to say this approach doesn't have it's problems:
It creates an obvious dependency between the generic objects object, any component that is designed to store a reference to itself inside objects, and any component that wishes to utilizes those references. Then again, using any kind of global state-management solution creates a similar dependency.
It's probably a bad solution if you have any doubt that FirstComponent will be mounted before you try to call it from within SecondComponent.
I've found that just having the reference to a React component won't allow you to do all the things that React components can do natively. For example, it won't work to call objects.FirstComponent.setState(). You can call a method in FirstComponent, which in turn can invoke its own setState(), but you can't invoke FirstComponent's setState() directly from within SecondComponent. Quite frankly, I think this is a good thing.
You can, however, directly access the state values from the components referenced in objects.
This should only be done with "global" components (components that functionally serve as singletons). If, for example, you had a simple UI component called BasicSpan that did little more than render a basic span tag, and you proceeded to use that component over and over again throughout your React app, I'm sure it would quickly become an unmanageable nightmare to try to place references to these simple components in the objects object and then try to intelligently manage calls to those components' internal methods.

you can send an event as props and call it from other component.
Say you have a class
Class A{
handleChange(evt)
{
this.setState({
name:evt.target.value
})
}
render{
return(
<div>
<ComponentB name={this.state.name}{ onChange={this.handleChange}/>
</div>
);
}
}
Child Component
Class B{
handleChange()
{
//logic
}
render{
return(
<div>
<input type="text" onChange={this.props.onChange}/>
{this.props.name}
</div>
);
}
Here in Component B when you change the input it will call the method
of class A and update state of A.
Now getting the updated state as props in component B will give you
the changed text that you just entered

Related

Sharing state among subcomponents in React

I'm currently developing an app that uses React in some parts of its UI to implement some complex feature that are very interactive. Some of these parts of the app, that are in fact React components, have become very complex in size.
This has led me to organize the code by dividing them in multiple subcomponents (and those in their own subcomponents, and so forth). The main problem is that some of the grandchildren of the main component might have the need to modify the state of another grandchildren that they're not related to. To do so, I end up having to have the state in the common parent and passing a lot of event handlers (methods of the parent component) to their children, and those children would need to pass it to their grandchildren.
As you can imagine, this is becoming some kind of a mess.
// MyComponent.js
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
list: [1, 2, 3, 4],
selected: '',
}
this.add = this.add.bind(this)
this.handleChange = this.handleChange.bind(this)
}
add() {
const newNumber = this.state.list[this.state.list.length - 1] + 1,
list = [...this.state.list, newNumber]
this.setState({list})
}
handleChange({target}) {
this.setState({
selected: target.value,
})
}
render() {
return (
<>
<List items={this.state.list} selected={this.state.selected} />
<Button onClick={this.add} />
<input type="text" value={this.state.selected} onChange={this.handleChange} />
</>
)
}
}
// Button.js
class Button extends React.Component {
render() {
return (
<button onClick={this.props.onClick}>Click me!</button>
);
}
}
// List.js
class List extends React.Component {
constructor(props) {
super(props)
this.refs = props.items.map(_ => React.createRef())
}
render() {
return (
<ul>
{this.props.items.map((item, key) =>
(<li ref={this.ref[key]} key={key}>{item}</li>)
)}
</ul>
);
}
}
In the previous dummy code you can see how I need to define the add() method in the MyCompoent component so that an action that happens in the Button component can modify what is being shown in List. Even tho this might seem like the obvious way to do it, my component has a big component tree, and a lot of methods, and most of then are lost in the tree, passing from parent to child until it reaches the component that should be expected.
I have done some research on the internet and it turns out this is a very common problem. In most sites, using Redux or other state management library is recommended. However, all the tutorials and guides I've seen that implement Redux with React seem to assume you're only using React to build your app, in Single Page Application sort of way. This is not my case.
Is there any way to share the state of a component to avoid this kind of problem? Is there, maybe, a way to use Redux multiple times for multiple components in the same app, where one store saves only the state for MyComponent and can be accessed by either List or any of its possible children?
Redux doesn't require your entire site to be in React. It implements a higher-level component that you can use with any React components even if they are embedded in another site.
You can look at React hooks to solve similar problems. Specifically, check out useContext() and useState().
You've used a lifting state up pattern in react in your example.
It's quite common you good approach but when you app is growing you need to pass all bunch of props throu the tree of components. It's difficult to maintain.
In this case you need to check out redux with separated store or useContext() hook.

Benefits of redux

I've started learning React without Redux or Flux and have been hearing a lot about Redux and how it seems to be the favourable pattern to use for managing state going forward. My understanding of it is that the entire state of the App lives in the store which I believe is at the top of the React tree. The various child components then 'subscribe' to various states that are relevant to them.
This is somewhat confusing for me as I thought the core structure of React is already setup in this way? Ie if my component has a certain state then to pass it down to its child components in order to use if further down the React tree I would need to add in this.state.example or this.props.example to a component. To me with this approach i'm 'subscribing' the component in a way as well..
Apologies if this is not the right place for questions like this but if someone could tell me what i'm missing here or the added benefit of Redux that would be very helpful!
You are on the right track on the subscribing portion, but what makes Redux wonderful and many other Flux like state management patterns is that you don't have to pass properties down the child chain just so you could update a childs component like so (you could if you wanted to, but not needed):
function Parent() {
return <ChildOne color="red" />
}
function ChildOne(props) {
return <ChildTwo color={props.color} />
}
function ChildTwo(props) {
return <h1>The Color was: {props.color}</h1>
}
It allows you to "dispatch" (a redux/flux term) an action to the state store to update a property on whichever object a component may be subscribed to.
A helpful library for that "connection" is react-redux. It has many capabilities, but the main that I see is connect which is a higher ordered component (HOC) that "wraps" your component with more logic including the part of the redux store that you want to subscribe to.
So the above could be:
export class Parent extends React.Component {
componentDidMount() {
this.props.dispatch(changeColor('red'));
}
render() {
return <ChildOne />
}
}
export default connect((state) => ({ //This property is the redux store
parent: state.parent,
}))(Parent) //higher order component that wraps the component with redux functionality
function ChildOne(){
return (
<ChildTwo />
);
}
export function ChildTwo(props) { //will have childTwo bound in props object
return (
<h1>The Color is: {props.childTwo.color}
);
}
export default connect((state) => ({ //This property is the redux store
childTwo: state.childTwo,
}))
Where the biggest difference is that you didn't have to pass the color from Parent down 2 levels to ChildTwo because it was "subscribed" to the childTwo object within the redux store and you connected that bit of state to the component so any change to the store will trigger the component to rerender from the state change.
The passing of properties and using Redux will make more sense with this medium post of Presentation and Container components, where passing of properties makes sense as you are only going down one child layer deep and the container component is handling logic such as ajax requests, or dispatches to parts of the redux store, etc.

What is the difference between React component and React component instance?

I am reading this and it says:
When a component is purely a result of props alone, no state, the
component can be written as a pure function avoiding the need to
create a React component instance.
What's the difference between a component and a component instance ?
Are they the same ?
EDIT:
What is the difference between Component and Component Instance ?
How do they relate to each-other ?
Conceptually ?
How are they represented in computer memory? How does the representation differ ?
What is a component and what is an instance of that component ? (In memory.) What kind of JS Object ?
Instance in what sense ? Object oriented sense ?
Is it true that every component can have (one or more) instance(s) ?
How many instances can a component have ?
Does it even make sense to say that an instance can be created for a/every react component ?
How are react component instances created and how are components created ?
Reason for asking:
I am trying to create a concept map of react to clarify the terminology and how they relate to each other.
Here is a draft:
The basic difference is, when it a Component, React will run/add all its Lifecycle methods. This will be useful when you have state in your component. When you use this component, React will create a React Component Instance which will have all the lifecycle methods and other hooks added to it.
class App extends React.Component{
...
}
In some cases, you won't use state. In those cases, adding all those lifecycle methods are unnecessary. So, React gives you an way to create an component which will have render alone. It is called PureComponent. When you use this, there is no need to create a new Component Instance because there is no lifecycle methods here. It'll just be a function which can take props and return React Elements.
class App extends React.PureComponent{
...
}
Hope this helps!
[Update]
What is a Component and a Component Instance?
Technically, a Component in React is a class or a function.
Example:
class App extends React.Component{
...
}
//stateless component
const App = (props) => {
...
}
When you use that component, it'll be instantiated, more like new App(). But, React does it by itself in a different way.
For Example:
render(){
return <App/> //Instance of the component App
}
Instances are required because, each instance can perform individually. Instances are a copy of original class.
Simple answer is, components will be a Class and component Instance will be the copy/instance of the class and will be used in render
Hope this explains!
A "React component instance" is just an instance that was created from a previously defined class component. See the example below (es6/JSX) which contains both props and state:
class MyComponentClass extends React.Component {
constructor(props) {
super(props);
// Set initial state
this.state = {
example: 'example'
};
}
render() {
return <div>
<div>{this.state.example}</div>
<div>{this.props.example}</div>
</div>;
}
}
If you have no need for state in your component you can use a pure, stateless, functional React component like so:
function MyStatelessFunctionalComponent(props) {
return <div>{this.props.example}</div>;
}
Here is some more information about stateless React components when they were introduced in React v0.14. Since then you have the ability to use hooks starting in React v16.8, which allow you to define a functional component that has state or makes use of the component lifecyle.
As mentioned in some other comments, there are many performance benefits when using stateless components. These types of components are perfect for when you want something purely presentational as an example.
Since there’s no state or lifecycle methods to worry about, the React team plans to avoid unnecessary checks and memory allocations in future releases.

How can I find all nested Components using React/Redux?

I am looking to validate a form with Redux. I am trying to use make a form component which will iterate through children and find various input components (not to be confused with a native <input>.
I know there are a lot of open source solutions, but I'd like to understand some mechanics before jumping into picking any. I have a Form component setup to test like this:
import React from 'react';
export default class Component extends React.Component {
componentDidMount() {
this._iterate(this.props.children);
}
render(){
return (
<form {...this.props}>{this.props.children}</form>
);
}
_iterate(children) {
React.Children.forEach(children, child => {
console.log(child);
if (child.props.children) {
console.log('get children');
this._iterate(child.props.children);
}
});
}
};
I then have another Component with a render like this:
render() {
return (
<div>
<Form>
<ComponentA />
<ComponentB />
</Form>
</div>
);
}
Now ComponentA or ComponentB might have a component that nests more components down the line. Within those components would be a React component I have made for Text, Select, etc.
The code above would just console.log the components, and any children of them, that are in this specific render. It does not jump down into ComponentA children.
Is there a solution to that?
This isn't a problem you really want to solve.
The power in react is largely around the design pattern it encourages, and what you're doing is breaking that pattern; Component's should only talk to their immediate children and respond to their immediate parents. If you need to go deeper than that, then the component in the middle needs to be responsible for passing that data.
Rather than trying to dig into the innards of ComponentA and ComponentB, those component's themselves should have the accessibility props that you need. I.e., <ComponentA onChange={whatever} errorMessage={whatever}/> etc. and then hooking those props to their children should occur within ComponentA.

Updating state in more than one component at a time

I have a listview component which consists of a number of child listitem components.
Each child listitem have a showSubMenu boolean state, which display a few extra buttons next to the list item.
This state should update in response to a user event, say, a click on the component DOM node.
childcomponent:
_handleClick() {
... mutate state
this.props.onClick() // call the onClick handler provided by the parent to update the state in parent
}
However, it feels somewhat wrong to update state like, as it mutates state in different places.
The other way i figured i could accomplish it was to call the this.props.onClick directly, and move the child state into the parent as a prop instead, and then do change the state there, and trickle it down as props.
Which, if any, of these approaches is idiomatic or preferable?
First of all, I think that the question's title doesn't describe very well what's your doubt. Is more an issue about where the state should go.
The theory of React says that you should put your state in the higher component that you can find for being the single source of truth for a set of components.
For each piece of state in your application:
Identify every component that renders something based on that state.
Find a common owner component (a single component above all the
components that need the state in the hierarchy).
Either the common
owner or another component higher up in the hierarchy should own the
state.
If you can't find a component where it makes sense to own the
state, create a new component simply for holding the state and add it
somewhere in the hierarchy above the common owner component.
However, a Software Engineer at Facebook said:
We started with large top level components which pull all the data
needed for their children, and pass it down through props. This leads
to a lot of cruft and irrelevant code in the intermediate components.
What we settled on, for the most part, is components declaring and
fetching the data they need themselves...
Sure, is talking about data fetched from stores but what im traying to say is that in some cases the theory is not the best option.
In this case i would say that the showSubMenu state only have sense for the list item to show a couple of buttons so its a good option put that state in the child component. I say is a good option because is a simple solution for a simple problem, the other option that you propose means having something like this:
var GroceryList = React.createClass({
handleClick: function(i) {
console.log('You clicked: ' + this.props.items[i]);
},
render: function() {
return (
<div>
{this.props.items.map(function(item, i) {
return (
<div onClick={this.handleClick.bind(this, i)} key={i}>{item} </div>
);
}, this)}
</div>
);
}
});
If, in a future, the list view has to get acknowledge of that state to show something for example, the state should be in the parent component.
However, i think it's a thin line and you can do wathever makes sense in your specific case, I have a very similar case in my app and it's a simple case so i put the state in the child. Tomorrow maybe i must change it and put the state in his parent.
With many components depending on same state and its mutation you will encounter two issues.
They are placed in component tree so far away that your state will have to be stored in a parent component very high up in the render tree.
Placing the state very high far away from children components you will have to pass them down through many components that should not be aware of this state.
THERE ARE TWO SOLUTIONS FOR THIS ISSUE!
Use React.createContext and user context provider to pass the data to child elements.
Use redux, and react-redux libraries to save your state in store and connect it to different components in your app. For your information react-redux library uses React.createContext methods under the hood.
EXAMPLES:
Create Context
const ThemeContext = React.createContext('light');
class App extends React.Component {
render() {
// Use a Provider to pass the current theme to the tree below.
// Any component can read it, no matter how deep it is.
// In this example, we're passing "dark" as the current value.
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
class ThemedButton extends React.Component {
// Assign a contextType to read the current theme context.
// React will find the closest theme Provider above and use its value.
// In this example, the current theme is "dark".
static contextType = ThemeContext;
render() {
return <Button theme={this.context} />;
}
}
}
// A component in the middle doesn't have to
// pass the theme down explicitly anymore.
function Toolbar() {
return (
<div>
<ThemedButton />
</div>
);
}
class ThemedButton extends React.Component {
// Assign a contextType to read the current theme context.
// React will find the closest theme Provider above and use its value.
// In this example, the current theme is "dark".
static contextType = ThemeContext;
render() {
return <Button theme={this.context} />;
}
}
REDUX AND REACT-REDUX
import { connect } from 'react-redux'
const App = props => {
return <div>{props.user}</div>
}
const mapStateToProps = state => {
return state
}
export default connect(mapStateToProps)(App)
For more information about redux and react-redux check out this link:
https://redux.js.org/recipes/writing-tests#connected-components

Resources