April 22, 2022

React Fragments With Examples

In this tutorial we'll see what is React.Fragment and how to use it.

Why React Fragment

When you write a React component there is a constraint that the JSX expression the component will render should always be wrapped with in a single parent element. Which means trying to write a component as given below results in an error.

const HelloWorld = (props) => {
  return (
    <h2>{props.title}</h2>
    <p>{props.message.greeting} {props.message.name}</p>
  );
}

The error you get for this component will be something like this-

Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...</>?

Most frequently <div> is used as a wrapper in such scenarios.

const HelloWorld = (props) => {
  return (
    <div>
      <h2>{props.title}</h2>
      <p>{props.message.greeting} {props.message.name}</p>
    </div>
  );
}

If I run this code and inspect it-

div as wrapper

With the React.Fragment you can get away with using such a wrapper when you need to return multiple elements. Here is the same component written using Fragment.

const HelloWorld = (props) => {
  return (
    <React.Fragment>
      <h2>{props.title}</h2>
      <p>{props.message.greeting} {props.message.name}</p>
    </React.Fragment>
  );
}

With that if you inspect the element, you can see that there is no wrapper now.

React.Fragment

React Fragment Usage

You may think what is the big deal? All Fragment did was to remove one extra <div>. Here are some reasons which should tell you the importance of React Fragments.

  1. With a big hierarchy when you break a component into several small components it does become a big deal actually. With using <div> as a wrapper you may end up with the rendered DOM having lot of nested <div> elements which are there just to wrap the elements rendered by the component. React.Fragment gives you a chance to get rid of such nested <div> elements.
  2. By removing such extra <div> elements, React.Fragment helps you in writing semantically correct HTML.
  3. Also helps you in shortening your rendered code which in turn takes less memory.

Here are few examples where you end up writing semantically wrong HTML because of this constraint of wrapping JSX elements.

1. Suppose you want to show some data in a table and you break that code into two components Table and Columns.

Table.js
import Columns from "./Columns";
const Table = () => {
  return (
    <table>
      <tr><Columns></Columns></tr>
    </table>
  )
}
export default Table;
Columns.js
const Columns = () => {
  return (
    <div>
      <td>First Column</td>
      <td>Second Column</td>
    </div>
  )
}

export default Columns;

Here you can see that <div> is used to wrap multiple <td> elements. With that you get <div> in between <tr> and <td> which is not semantically correct HTML.

By using Fragment you can get rid of this unnecessary div.

<React.Fragment>
  <td>First Column</td>
  <td>Second Column</td>
</React.Fragment>
React Fragment example

2. In this another example we have to show a list of products. There are separate components for Products and ProductItems.

Products.js
import ProductItem from "./ProductItem";

const INIT_PRODUCT_CATALOG = [
  { id: 1, name: 'Laptop', price: 455.50 },
  { id: 2, name: 'Mouse', price: 15.89 },
  { id: 3, name: 'USB', price: 10.00 },
  { id: 4, name: 'HDD', price: 55.50 },
];
const Products = () => {
  return (
    <ul>
      {INIT_PRODUCT_CATALOG.map((val, key) => <ProductItem key={key} item={val} />)}
    </ul>
  );
}

export default Products;
ProductItem.js
const ProductItem = (props) => {
  return (
    <div>
      <li>------Next Product--------</li>
      <li>{props.item.id}</li>
      <li>{props.item.name}</li>
      <li>{props.item.price}</li>
   </div>
  )
}

export default ProductItem;

Here you can see that <div> is used to wrap multiple <li> elements. With that you get <div> in between <ul> and <li> which is not semantically correct HTML. By using Fragment you can get rid of this unnecessary div.

<React.Fragment>
    <li>------Next Product--------</li>
    <li>{props.item.id}</li>
    <li>{props.item.name}</li>
    <li>{props.item.price}</li>
</React.Fragment>

Fragment short syntax

There is a shorter syntax for declaring fragments which looks like empty tags <></>. With empty tags you don't need to import React and no need to write <React.Fragment>, here is the previous example where <React.Fragement> is replaced with empty tags.

<>
    <li>------Next Product--------</li>
    <li>{props.item.id}</li>
    <li>{props.item.name}</li>
    <li>{props.item.price}</li>
</>

One drawback of using empty tags is that you can’t use keys with them.

Key with Fragments

With Fragment you can pass a key attribute, that may be required when you map a collection to an array of fragments. Fragment with a key is called a Keyed Fragment. Note that, key is the only attribute that can be passed to Fragment.

const INIT_PRODUCT_CATALOG = [
    { id: 1, name: 'Laptop', price: 455.50 },
    { id: 2, name: 'Mouse', price: 15.89 },
    { id: 3, name: 'USB', price: 10.00 },
    { id: 4, name: 'HDD', price: 55.50 },
];
const Products = () => {
    return (
        <ul>
            {INIT_PRODUCT_CATALOG.map((item) => <React.Fragment key={item.id} >
                    <li>{item.id} {item.name} {item.price}</li>
                </React.Fragment>
            )}
        </ul>
    );
}

export default Products;

That's all for the topic React Fragments With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

No comments:

Post a Comment