ReactJS - Fragments



Fragment is the simple solution to group multiple react elements without adding extra markup in the DOM.

In React, render method of a component is allowed to return a react element. For a component to return multiple elements, the elements needs to be wrapped into a generic container element. For example, to return multiple p elements, it should be wrapped around a div element as shown below −

<div>
   <p>One</p>
   <p>Two
   </p>
</div>

Wrapping a generic root element is fine for most of the scenarios, but certain scenario needs special handling. They are as follows −

  • Certain elements such as li, td, etc., may not be wrapped around generic element.

  • When the component needs to return only a partial list of elements (which will be eventually wrapped in the parent component).

Let us write a simple component to better understand our problem. The functionality of the component is to return a partial list of customers as shown below −

<li>John</li>
<li>Peter</li>

Create a new application using create-react-app and start the application.

create-react-app myapp
cd myapp
npm start

Create a component, ListOfCustomer under components folder (src/components/ListOfCustomer.js)

import React from 'react'
class ListOfCustomer extends React.Component {
   constructor(props) {
      super(props);
   }
   render() {
      console.log(this.props)
      var names = this.props['names'];
      var namesList = names.map(
         (name, index) => <li>{name}</li>
      )
      return <ul>{namesList}</ul>
   }
}
export default ListOfCustomer

Here, the component loop over the names property and render it into a list of li elements.

Now, use the component in our root component (App.js)

import ListOfCustomer from './components/ListOfCustomer';
function App() {
   var names = ["John", "Peter"]
   return (
      <ul>
         <ListOfCustomer names={names} />
      </ul>
   );
}
export default App;

This will result in rendering of multiple ul as shown below −

<ul><ul><li>John</li><li>Peter</li></ul></ul>

Let us change the component to use React.Fragment

import React, { Fragment } from 'react'
class ListOfCustomer extends React.Component {
   constructor(props) {
      super(props);
   }
   render() {
      console.log(this.props)
      var names = this.props['names'];
      var namesList = names.map(
         (name, index) => <li>{name}</li>
      )
      return <React.Fragment>{namesList}</React.Fragment>
   }
}
export default ListOfCustomer

Now, our component renders valid HTML document.

<ul><li>John</li><li>Peter</li></ul>

Keyed Fragments

In the above example, React throws a warning in the developer console as shown below −

Warning: Each child in a list should have a unique "key" prop.
Check the render method of `ListOfCustomer`. See https://reactjs.org/link/warning-keys for more information.
li
ListOfCustomer@http://localhost:3000/main.4bbe8fa95c723e648ff5.hot-update.js:26:10
ul
App
render - ListOfCustomer.js:9

As the warning says, React excepts unique key for each element in the list. It uses the key to identify which elements are changed. are added or are removed. React.Fragment allows a key to be passed through its key attribute. React will use it internally to render only the modified item in the list. Let us change our code and add key to React.Fragment as shown below −

import React, { Fragment } from 'react'
class ListOfCustomer extends React.Component {
   constructor(props) {
      super(props);
   }
   render() {
      console.log(this.props)
      var names = this.props['names'];
      var namesList = names.map(
         (name, index) => <li key={index}>{name}</li>
      )
      return <React.Fragment>{namesList}</React.Fragment>
   }
}
export default ListOfCustomer

This will remove the error.

Short syntax

React.Fragment has an alternative shorter syntax, which is both easy to use and readable.

<>
JSX element
</>

Let us change our code to accommodate the shorter syntax. The updated code is as follows −

import React, { Fragment } from 'react'
class ListOfCustomer extends React.Component {
   constructor(props) {
      super(props);
   }
   render() {
      console.log(this.props)
      var names = this.props['names'];
      var namesList = names.map(
         (name, index) => <li key={index}>{name}</li>
      )
      return <>{namesList}</>
   }
}
export default ListOfCustomer
Advertisements