Skip to main content

Understanding Fragments in React

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 BodyComponentand HeaderComponentcomponents:
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

Popular posts from this blog

Warren Buffett: “Really Successful People Say No To Almost Everything”

When I tell people that Warren Buffett follows the 5-Hour Rule and spends 80% of his time reading and thinking, they have an immediate and predictable reaction: “Well, he can do that because he’s Warren Buffett, one of the richest people in the world. I could never do that.” While this response may help people feel better about themselves, it certainly won’t make them smarter. Because the reality is: Buffett has spent most of his time reading and thinking since he was in grade school. Having more money or managing a large company doesn’t magically give you free time. Having free time is never the default. People don’t just fall into huge blocks of free time unless they retire. Rather, free time is the result of strategy. It’s the result of looking at time differently. Curious about Buffett’s unique strategies, I’ve read several books about him, read most of his annual letters to stockholders, and watched nearly all of his interviews. And make no mistake about it… behind Buffett’s jovia…

This Is Exactly How You Should Train Yourself To Be Smarter [Infographic]

Design inspired by the Cognitive Bias Codex
View the high resolution version of the infographic by clicking here. Out of all the interventions we can do to make smarter decisions in our life and career, mastering the most useful and universal mental models is arguably the most important. Over the last few months, I’ve written about how many of the most successful self-made billionaire entrepreneurs like Ray Dalio, Elon Musk, and Charlie Munger swear by mental models… “Developing the habit of mastering the multiple models which underlie reality is the best thing you can do. “ — Charlie Munger “Those who understand more of them and understand them well [principles / mental models] know how to interact with the world more effectively than those who know fewer of them or know them less well. “ — Ray Dalio “It is important to view knowledge as sort of a semantic tree — make sure you understand the fundamental principles, i.e. the trunk and big branches, before you get into the leav…

If you want to be massively successful, do NOT set ambitious goals, according to studies

The conventional model to having great success in your career is setting and ardently pursuing big, hairy, audacious goals (BHAGs), even if you have no idea how you’re going to achieve them when you start. Want to build a billion dollar company? Set the goal and work backward from long-term goals to medium-term goals to short-term goals to today’s to-do list. Then take action, measure your progress along the way, and constantly course correct so you’re always on the most direct path (that you’re aware of) toward your ultimate goal. Want to cure cancer? Set the goal and work backward. Measure your progress. Want to find the love of your life or be happy? Set the goal. Rinse and repeat. This goals model is so obvious in our culture, it goes without saying. It’s central to our collective success recipe. Goals give motivation, meaning, and focus when we feel lazy or distracted — at least so we’re told. However, recent research from the field of artificial intelligence is putting a nail in t…