Reputation: 6347
I know the way we pass props to children when using this.props.children
the following way:
React.Children.map(this.props.children, (child: any, index: number) => {
return React.cloneElement(child, {
Visibility: this.state.visibility,
});
});
To pass prop to only the first child I can use the index and wrap the cloneElement
call in an if (index === 0)
, but this won't stop map
from interating over all the children.
I'm wondering if there's a way I can break the loop right after index 0 is reached. Thanks!
Upvotes: 3
Views: 2567
Reputation: 59531
Since you only need the the first item, there is no need to loop through them.
React.Children.toArray()
will always give you an array, regardless if you have one or multiple children, which saves you some of the checks in T.J's answer.
So here is a slightly shorter (and imo cleaner) solution:
const child = React.Children.toArray(children)[0];
if (child) {
return React.cloneElement(child, {Visibility: this.state.visibility});
}
return null;
React.Children.toArray(children)
Returns the children opaque data structure as a flat array with keys assigned to each child. Useful if you want to manipulate collections of children in your render methods, especially if you want to reorder or slice this.props.children before passing it down.
Upvotes: 4
Reputation: 1075337
I'm wondering if there's a way I can break the loop right after index 0 is reached. Thanks!
Don't use map
at all, then, if you only want the first child.
const child = (Array.isArray(this.props.children) ? this.props.children[0] : this.props.children) || null;
return child && React.cloneElement(
child,
{Visibility: this.state.visibility }
);
That first bit:
const child = (Array.isArray(this.props.children) ? this.props.children[0] : this.props.children) || null;
...guards against the fact that this.props.children
is only an array when there are multiple children (details); otherwise, it's the single child passed, or undefined
if no children are passed (which we convert to null
so we can directly return it from render
).
Then the return child &&
guards aginst the possibility there were no children at all.
Example with all those situations:
class Example extends React.Component {
constructor(...args) {
super(...args);
this.state = {
visibility: true
};
}
render() {
const child = (Array.isArray(this.props.children) ? this.props.children[0] : this.props.children) || null;
return child && React.cloneElement(
child,
{Visibility: String(this.state.visibility) }
);
}
}
const Child = props => <div>Visibility: {props.Visibility}</div>;
ReactDOM.render(
<div>
<Example />
<Example><Child/></Example>
<Example><Child/><Child/></Example>
</div>,
document.getElementById("root")
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
Upvotes: 4