We all might have used {this.props.children} inside the React Components to get hold of the child elements.
The {this.props.children} is what can be called as an opaque data structure. There are very limited operations or manipulations that we can perform on this. That is where the React.Children api comes into picture.
React provides us with a Children api that helps in dealing with this opaque data structure.
Let's take a look at the use cases using an example -
ParentElement.js
import { Component } from "react";
class ParentElement extends Component {
render() {
// Inside the Parent component we are directly displaying the props.children
return <div>{this.props.children}</div>;
}
}
export default ParentElement;
ChildElement.js
import { Component } from "react";
import Parent from "./ParentElement";
// This is a simple example for using the Parent component
// And accessing the child elements wrapped inside the Parent
class ChildElement extends Component {
render() {
return (
<Parent>
<div>Child 1</div>
<div>Child 2</div>
<div>Child 3</div>
<div>Child 4</div>
</Parent>
);
}
}
export default ChildElement;
Output to the following code
Now let us look at the scenarios that we might encounter.
1. React.Children.toArray()
Scenario 1 - We need to display only the first Child inside the ParentElement even though we are getting 4 div's as immediate child elements from {this.props.children}
The data that we get from {this.props.children} is called opaque data. This is treated as a single entity and we cannot distribute this in the form of an array. In order to convert this to an array, we can use the toArray method from the React.Children api
This method takes in the this.props.children as argument and converts it to an array with each immediate child forming the elements of the array.
Let us take a look at this implementation and try to solve the issue mentioned in scenario 1.
ParentElement.js
import React, { Component } from "react";
class ParentElement extends Component {
render() {
const { children } = this.props;
// toArray method is called to convert this.props.children to an array
// We are then referencing the first element using index 0
return <div>{React.Children.toArray(children)[0]}</div>;
}
}
export default ParentElement;
Output after implementing the toArray method
2. React.Children.count()
Scenario 2 - We need to get the count of the immediate child elements.
Again, this is impossible to calculate on this.props.children as it is considered as a single entity.
React.Children gives us the count method to do this.
It takes in this .props.children as argument and returns the count of the immediate child elements.
ParentElement.js
import React, { Component } from "react";
class ParentElement extends Component {
render() {
const { children } = this.props;
// count method is used to count the immediate child elements in this.props.children
// Even though the count is 4, we are only displaying Child 1
return (
<div>
<p>
Total Count of Children: {React.Children.count(this.props.children)}
</p>
{React.Children.toArray(children)[0]}
</div>
);
}
}
export default ParentElement;
3. React.Children.only()
Scenario - 3 - We need to make sure that the this.props.children is such that it only has 1 element as its immediate child. This one element in turn can have multiple child elements inside it. But on the highest level we need to ensure that there is only one element.
We can use the only method from React.Children api for this.
Let us look at the code below -
ChildElement.js
import { Component } from "react";
import Parent from "./ParentElement";
// This is a simple example for using the Parent component
// And accessing the child elements wrapped inside the Parent
class ChildElement extends Component {
render() {
return (
// There are 4 immediate child elements here
<Parent>
<div>Child 1</div>
<div>Child 2</div>
<div>Child 3</div>
<div>Child 4</div>
</Parent>
);
}
}
export default ChildElement;
ParentElement.js
import React, { Component } from "react";
class ParentElement extends Component {
render() {
const { children } = this.props;
// count method is used to count the immediate child elements in this.props.children
// Even though the count is 4, we are only displaying Child 1
return (
<div>
<p>
Total Count of Children: {React.Children.count(this.props.children)}
</p>
{/* Making use of the only method */}
{React.Children.only(children)}
</div>
);
}
}
export default ParentElement;
Output when there are 4 child elements
Now, in order to comply with the only method, we will wrap the 4 Child elements in a single div
ChildElement.js
import { Component } from "react";
import Parent from "./ParentElement";
// This is a simple example for using the Parent component
// And accessing the child elements wrapped inside the Parent
class ChildElement extends Component {
render() {
return (
// There are 4 immediate child elements here
<Parent>
{/* Wrapping the child elements inside a single element */}
<div>
<div>Child 1</div>
<div>Child 2</div>
<div>Child 3</div>
<div>Child 4</div>
</div>
</Parent>
);
}
}
export default ChildElement;
Now the output will change to -
This is working now as we changed the html structure and added a parent div to the 4 Child elements which will make sure that there is only one immediate child element when using the method React.Children.only
4. React.Children.map()
Scenario 4 - I need to iterate through all the individual child items and then convert this into a button element with a specific style.
This is again not possible directly via this.props.children.
There is a map method provided to us by React.Children which works very similar to the array map method. It returns an array of items as its output.
Let us look at the code below.
ChildElement.js
import { Component } from "react";
import Parent from "./ParentElement";
// This is a simple example for using the Parent component
// And accessing the child elements wrapped inside the Parent
class ChildElement extends Component {
render() {
return (
// There are 4 immediate child elements here
<Parent>
{/* Wrapping the child elements inside a single element */}
<div>
<div>Child 1</div>
<div>Child 2</div>
<div>Child 3</div>
<div>Child 4</div>
</div>
</Parent>
);
}
}
export default ChildElement;
ParentElement.js
import React, { Component } from "react";
const btnStyle = {
background: "green",
color: "#fff",
fontSize: "18px",
fontWeight: "bold",
border: "1px solid white",
marginTop: "5px",
padding: "3px",
};
class ParentElement extends Component {
render() {
const { children } = this.props;
// count method is used to count the immediate child elements in this.props.children
// Even though the count is 4, we are only displaying Child 1
return (
<div>
<p>
Total Count of Children: {React.Children.count(this.props.children)}
</p>
{/* Making use of the only method */}
{React.Children.map(children, (child) => {
return <button style={btnStyle}>{child}</button>;
})}
</div>
);
}
}
export default ParentElement;
Output of the above code
Now, if you check this output, we can see that all the 4 Child elements are wrapped inside a single button. This is because in the ChildElement.js we have wrapped all the 4 Child element divs under a single parent div. The map method iterates only through the immediate children.
Now let us change the html structure of ChildElement.js and remove the parent div
import { Component } from "react";
import Parent from "./ParentElement";
// This is a simple example for using the Parent component
// And accessing the child elements wrapped inside the Parent
class ChildElement extends Component {
render() {
return (
// There are 4 immediate child elements here
<Parent>
{/* Removed the parent div from here */}
<div>Child 1</div>
<div>Child 2</div>
<div>Child 3</div>
<div>Child 4</div>
</Parent>
);
}
}
export default ChildElement;
Output for the above code -
As we can see in the image, now we get 4 distinct buttons with style applied.
5. React.Children.forEach()
This method is also very similar to the map method. The only difference is that it does not return an array. It simply allows the user to iterate over all the immediate child elements.
// This is used to print the values inside the individual child elements
React.Children.forEach(children, (child) => {
console.log(child.props.children);
});
Output
I hope this helped to give you a fair understanding of the Children api in react and the common methods available to us and their use cases.
Happy Coding!
Top comments (0)