Understanding Fragments in React

Understanding Fragments in React

Understanding Fragments in React

  • by admin
  • Web Development

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”.

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 solve 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 second 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 !!!

Tags: React,Fragments,JavaScript