UI elements have a hierarchical structure. For example, it is the card in Bootstrap:
<div class="card">
<img class="card-img-top" src="..." alt="Card image cap">
<div class="card-body">
<h4 class="card-title">Card title</h4>
<p class="card-text">
Some quick example text to build on the card title and make up the card's content
</p>
<a href="#" class="btn btn-primary">Go somewhere</a>
</div>
</div>
HTML conforms to the nature of UI and naturally allows you to create compositions of elements by nesting tags within each other.
JSX works the same way. So far, we have talked about this feature for embedded components. Now it's time to learn how to repeat this behavior in self-written ones.
Here you can see the example, based on the <Alert />
component from Bootstrap:
See the Pen YxgWVm by Hexlet (@hexlet) on CodePen.
In the example above, only the main div
is mandatory. The content depends on the specific situation. It's substituted using the children
property.
See the Pen js_react_children_alert_component by Hexlet (@hexlet) on CodePen.
Note that we use the component as a paired tag in JSX:
const vdom = (
<Alert>
<p>Don't forget to use margin utilities to keep things nice and tidy</p>
</Alert>
);
Everything between the opening and closing tags goes inside the children
prop.
But beware that the children
property data type depends on the content. For example, the property will be undefined
when we use the tag as a single <div />
.
If this content is a string, it'll be inside children
. After some processing, anyway. JSX removes whitespace from the beginning and end of a string, including blank lines. The following examples will be displayed in the same way:
<div>Hello World</div>
<div>
Hello World
</div>
<div>
Hello
World
</div>
<div>
Hello World
</div>
Any single child component will also be represented in children
. In all other cases, children
will contain an array.
If you look closely at the React documentation, you'll see the definition of children
as an opaque data structure. In other words, we can convey anything on the outside, so we can't unequivocally rely on the type of this prop.
This kind of behavior can lead to hard-to-find mistakes. For example, checking this.props.children.length
doesn't always give the number of children. If children
children is a single element, such as a string, then the length
property will return the length of that string:
class MyComponent extends React.Component {
render() {
const { children } = this.props
return <p>Count: {children.length}</p>
}
}
// <p>Count: 4</p>
<MyComponent>Text</MyComponent>
It is why React offers functions specifically designed to manipulate the children
prop, which we can access through React.Children
. These functions are well-equipped to handle the intricacies of children
. They automatically verify its type and perform appropriate checks based on the data type.
React.Children.map()
In the lesson on processing collections, you learned that when working with a list in React, we should assign a key
prop to each item. If using React.Children.map
, React won't throw a warning if you fail to do so. This omission is intentional, as descendants often lack unique identifiers.
React.Children.count()
class ChildrenCounter extends React.Component {
render() {
const { children } = this.props
return <p>Count: {React.Children.count(children)}</p>
}
}
// Count: 1
<ChildrenCounter>
Second!
</ChildrenCounter>
// Count: 2
<ChildrenCounter>
<p>First</p>
<ChildComponent />
</ChildrenCounter>
// Count: 2
<ChildrenCounter>
{() => <h1>First!</h1>} // will be skipped because it's not a dom-element
Second!
<p>Third!</p>
</ChildrenCounter>
In addition to the above, you may need to handle child elements before output by changing a part in their props. Of course, we can't do it directly because props are immutable. You can achieve this behavior by cloning elements with React.cloneElement()
.
Are there any more questions? Ask them in the Discussion section.
The Hexlet support team or other students will answer you.
For full access to the course you need a professional subscription.
A professional subscription will give you full access to all Hexlet courses, projects and lifetime access to the theory of lessons learned. You can cancel your subscription at any time.