Today we learn something new and advanced in Reactjs we all know in Reactjs props are used to communicate with the other components.
Now we learn something different called Compound Components in React using some top-level apis.
1.React.Children.map
2.React.cloneElement()
Our final output should like the below image.
Accordion Component code
<Accordion>
<Heading>Heading 1</Heading>
<Text>
“You've gotta dance like there's nobody watching, Love like you'll
never be hurt, Sing like there's nobody listening, And live like it's
heaven on earth.” ― William W. Purkey
</Text>
<Heading>Heading 2</Heading>
<Text>
“Don’t walk in front of me… I may not follow Don’t walk behind me… I
may not lead Walk beside me… just be my friend” ― Albert Camus
</Text>
<Heading>Heading 3</Heading>
<Text>
“Darkness cannot drive out darkness: only light can do that. Hate
cannot drive out hate: only love can do that.” ― Martin Luther King
Jr., A Testament of Hope: The Essential Writings and Speeches
</Text>
<Heading>Heading 4</Heading>
<Text>
Mauris mauris ante, blandit et, ultrices a, suscipit eget, quam.
Integer ut neque. Vivamus nisi metus, molestie vel, gravida in,
condimentum sit amet, nunc. Nam a nibh. Donec suscipit eros. Nam mi.
Proin viverra leo ut odio. Curabitur malesuada. Vestibulum a velit eu
ante scelerisque vulputate.
</Text>
<Heading>Heading 5</Heading>
<Text>
“I believe that everything happens for a reason. People change so that
you can learn to let go, things go wrong so that you appreciate them
when they're right, you believe lies so you eventually learn to trust
no one but yourself, and sometimes good things fall apart so better
things can fall together.” ― Marilyn Monroe
</Text>
</Accordion>
Now let's get into the logic in above code Accordion component is holding the different types of children example Heading, Text.
Accordion Component implementation.
class Accordion extends React.Component {
state = {
active: -1
};
onShow = i => {
this.setState({
active: i
});
};
render() {
const children = React.Children.map(this.props.children, (child, i) => {
return React.cloneElement(child, {
heading: this.state.active === i,
text: this.state.active + 1 === i,
onShow: () => this.onShow(i)
});
});
return <div className="accordion">{children}</div>;
}
}
what above code does is instead of returning the children we are mapping the children using React.Children.map and cloning the child by passing some state to the Children it means we are passing state down to the children.
Heading Component.
class Heading extends React. Component {
render() {
const { heading, onShow, children } = this.props;
return (
<h2 className={heading ? "active" : "normal"} onClick={onShow}>
{children}
</h2>
);
}
}
Text Component
class Text extends React.Component {
contentBox = () => {
if (!this.props.text) {
return null;
} else {
return (
<div className="content-box">
<p className="text">{this.props.children}</p>
</div>
);
}
};
render() {
return this.contentBox();
}
}
Other example
Have you seen there is no state present inside the Text or Heading components.
Hope you guys enjoyed....
Top comments (3)
How is this any different than passing the same data via props?
I don't understand the benefit of doing it this way instead of doing it the "proper" way via properties.
If anything, you are making a simple concept harder to understand and read.
Also, aren't you dropping performance by cloning the elements on every render call?
There is only single state present in the entire code and also the state is accessible to all child components if I need to change the state from the heading component all components are updated with updated state.
If i need to render the Text component above and heading component below still it works without changing any code in the text component or heading component.
Magic!!!!!