You have a parent component that acts as a wrapper around other components. Can it pass props to its children?
Let’s say we have a component called RadioGroup
that has a number of children components called RadioInput
, like so:
<RadioGroup>
<RadioInput value="first">First</RadioInput>
<RadioInput value="second">Second</RadioInput>
<RadioInput value="third">Third</RadioInput>
</RadioGroup>
The RadioInput
component just renders an <input>
element:
const RadioInput = (props) => {
return (
<div>
<label>
{props.children}
<input type="radio" name={props.name} value={props.value} />
</label>
</div>
);
};
To group input
elements together, they must have the same name
attribute. We can do it manually, like this:
<RadioGroup>
<RadioInput name="group1" value="first">First</RadioInput>
<RadioInput name="group1" value="second">Second</RadioInput>
<RadioInput name="group1" value="third">Third</RadioInput>
</RadioGroup>
But is there a way to add the name
attribute programmatically by passing it as a prop to the parent component? For example:
<RadioGroup name="group1">
<RadioInput value="first">First</RadioInput>
<RadioInput value="second">Second</RadioInput>
<RadioInput value="third">Third</RadioInput>
</RadioGroup>
To pass additional props to the children from within the parent component, you need to clone the children components using React.cloneElement()
.
The React.cloneElement()
API clones an element and returns a new React element. The cool thing is that the resulting element will have all of the original element’s props, with the new props merged in.
For example:
const newElement = React.cloneElement(originalElement, {
extraProp: "Some extra prop",
});
Here, newElement
will have all the props from the originalElement
, along with the extraProp
.
In our original example, let’s say we have the RadioGroup
component defined as follows:
const RadioGroup = (props) => {
return <div>{props.children}</div>;
};
You can write a function renderChildren
and use it inside the return
statement:
const RadioGroup = (props) => {
const renderChildren = () => {
return props.children;
};
return <div>{renderChildren()}</div>;
};
Now you can loop over all props.children
using the map
function and clone each child with React.cloneElement()
. While cloning we will add name
to the existing props, like so:
const RadioGroup = (props) => {
const renderChildren = () => {
return React.Children.map(props.children, (child) => {
return React.cloneElement(child, {
name: props.name,
});
});
};
return <div>{renderChildren()}</div>;
};
This way all the children components will have the name
attribute set to whatever you pass to the RadioGroup
component.