
This is another post in our React Series, we have learned many React concepts in our past posts in our React series:
- Default props
- Prop types
- Render props
- Higher-order components
- Context
In this post, we will look at another common issue in React. Read on. As always, when working with your React components, I’d advise making them reusable with tools like Bit so that you won’t have to rewrite them every time. It also nice to share your components organized in a visual gallery, right?
Problem Statement
Have you tried rendering multiple React components like this:
class ParentC extends React.Component { render() { return ( <ChildC /> <ChildC /> ) } }
class ChildC extends React.Component { render() { return ( <h1> Child Component </h1> ) } }
or render a list of nodes like this:
class ChildComponent extends React.Component { render() { return ( <h1>Hello Child Component</h1> <h1>Hello Child Component</h1> ) } }
If you are using VS Code with JSX support extensions you will have a warning showing: “JSX parent expressions must have one parent element”.
![]() |
MakCorps - Hotel Price Comparison API |
To make the warning go away you will be forced to add an extra div tag as the parent element to your JSX markup.
class ParentC extends React.Component { render() { return ( <div> <ChildComponent /> <ChildComponent /> </div> ) } }
class ChildComponent extends React.Component { render() { return ( <div> <h1>Hello Child Component</h1> <h1>Hello Child Component</h1> </div> ) } }
The problem here is that the div tags is a bit awkward. There are cases in HTML where an extra div might destructure the DOM. For instance, when using a table in your components.
We want to render users details in tabular form using table element in HTML. We want to render the below code in React:
<table> <tr> <th>Name</th> <th>Occupation</th> <th>Age</th> </tr> <tr> <td>Chidume Nnamdi</td> <td>Software Dev</td> <td>27</td> </tr> <tr> <td>Row Ekemezie</td> <td>Software Dev</td> <td>? :)</td> </tr> </table>
We would create components to render each facet of the table element. A HeaderComponent would render the table head. and a BodyComponent would render the body of the table. TableComponent would render the table skeleton with the HeaderComponent and BodyComponent like this:
class TableComponent extends React.Component { render() { return ( <table> <tr> <HeaderComponent /> </tr> <tr> <BodyComponent /> </tr> </table> ) } }
Our HeaderComponent should look like his:
class HeaderComponent extends React.Component { render() { return ( <th>Name</th> <th>Occupation</th> <th>Age</th> ) } }
And BodyComponent would look like this:
class BodyComponent extends React.Component { render() { return ( <td>Chidume Nnamdi</td> <td>Software Dev</td> <td>27</td> ) } }
The problem with HeaderComponent and BodyComponent is that they return multiple nodes. React would warn to enclose their markup in an enclosing tag.
So we would try to do something like this to remove the warning:
class HeaderComponent extends React.Component { render() { return ( <div> <th>Name</th> <th>Occupation</th> <th>Age</th> </div> ) } }
class BodyComponent extends React.Component { render() { return ( <div> <td>Chidume Nnamdi</td> <td>Software Dev</td> <td>27</td> </div> ) } }
We enclosed the markup in a div tag. The output of the Table component would now be this:
<table> <tr> <div> <th>Name</th> <th>Occupation</th> <th>Age</th> </div> </tr> <tr> <div> <td>Chidume Nnamdi</td> <td>Software Dev</td> <td>27</td> </div> </tr> </table>
The above is the wrong output of the table element. The div element shouldn’t be present. React components are meant to return elements but they must be enclosed in a parent tag, multiple elements cannot be returned. But adding extra node sometimes results in the wrong formatting of our html output as we saw above.
How do we solve this problem? How do we return enclosed JSX elements without affecting the rendered output on the DOM?
React provided a solution to it in the form of Fragments.
Solution — Fragments
Fragments lets you group a list of children without adding extra nodes to the DOM — Reactjs Blog
Using
<React.Fragment>...</React.Fragment>
, we can add a parent tag to our JSx elements without adding an extra node to the DOM. React.Fragment outputs no HTMLElement.
Let’s use to sove our first problem:
class ParentC extends React.Component { render() { return ( <ChildC /> <ChildC /> ) } }
class ChildC extends React.Component { render() { return ( <h1> Child Component </h1> ) } }
Now, we will enclose:
return ( <ChildC /> <ChildC /> )
in
React.Fragment
. It would now look like this:class ParentC extends React.Component { render() { return ( <React.Fragment> <ChildC /> <ChildC /> </React.Fragment> ) } }
Next, our secound example:
class ParentC extends React.Component { render() { return ( <div> <ChildComponent /> <ChildComponent /> </div> ) } }
class ChildComponent extends React.Component { render() { return ( <div> <h1>Hello Child Component</h1> <h1>Hello Child Component</h1> </div> ) } }
We would remove the
div
tags and add React.Fragment
in their place:class ParentC extends React.Component { render() { return ( <React.Fragment> <ChildComponent /> <ChildComponent /> </React.Fragment> ) } }
class ChildComponent extends React.Component { render() { return ( <React.Fragment> <h1>Hello Child Component</h1> <h1>Hello Child Component</h1> </React.Fragment> ) } }
Then, in our third example, we replace the extra div tags in the BodyComponent and HeaderComponent with React.Fragment:
class HeaderComponent extends React.Component { render() { return ( <div> <th>Name</th> <th>Occupation</th> <th>Age</th> </div> ) } }
class BodyComponent extends React.Component { render() { return ( <div> <td>Chidume Nnamdi</td> <td>Software Dev</td> <td>27</td> </div> ) } }
| | | v
class HeaderComponent extends React.Component { render() { return ( <React.Fragment> <th>Name</th> <th>Occupation</th> <th>Age</th> </React.Fragment> ) } }
class BodyComponent extends React.Component { render() { return ( <React.Fragment> <td>Chidume Nnamdi</td> <td>Software Dev</td> <td>27</td> </React.Fragment> ) } }
The table would render like this:
<table> <tr> <th>Name</th> <th>Occupation</th> <th>Age</th> </tr> <tr> <td>Chidume Nnamdi</td> <td>Software Dev</td> <td>27</td> </tr> </table>
As we want, with no extra div tags !!!
If writing
React.Fragment
every time is too long for you. React.Fragment has a shorthand syntax that you can use. It is <>...</>
. So our BodyComponent
and HeaderComponent
components:class HeaderComponent extends React.Component { render() { return ( <React.Fragment> <th>Name</th> <th>Occupation</th> <th>Age</th> </React.Fragment> ) } }
class BodyComponent extends React.Component { render() { return ( <React.Fragment> <td>Chidume Nnamdi</td> <td>Software Dev</td> <td>27</td> </React.Fragment> ) } }
can also be written like this:
class HeaderComponent extends React.Component { render() { return ( <> <th>Name</th> <th>Occupation</th> <th>Age</th> </> ) } }
class BodyComponent extends React.Component { render() { return ( <> <td>Chidume Nnamdi</td> <td>Software Dev</td> <td>27</td> </> ) } }
Conclusion
In this post, we saw first saw a problem of not being able to return multiple elements and the solution to it using React.Fragment also saw the shorthand syntax of React.Fragment and how to use it.
You see with React.Fragment, we enjoy the benefit of returning multiple elements without having to add extra tags or div tags that wrap our elements and clutter the DOM.
If you have any question regarding this or anything I should add, correct or remove, feel free to comment, email or DM me. Thanks !!!
Comments
Post a Comment