DEV Community

Cover image for React Fragments in 5 minutes (with examples)
Kairat
Kairat

Posted on • Edited on

React Fragments in 5 minutes (with examples)

multiple JSX elements returned error

And you think to yourself: "Oh God, what have I done wrong again?"

oh god, not again meme

But luckily for you (and for all of us - React developers), this time the problem is super simple.

Let's take a look at the code that caused the problem.

import React from "react";

const Fragment = () => {
  return 
  <div>Fragments</div>
  <p>in React</p>
  ;
};

export default Fragment;
Enter fullscreen mode Exit fullscreen mode

As you can see, we are trying to return two JSX elements from our Fragment component.

And, as you probably understand, this is the root of our problem.

So, why?

Isn't it a common situation when you need to return multiple elements from a component?

And you are right - this is a common pattern in React.

But you have to remember:

Component must return only one parent element and not more, not less.


What can we do about this?

So, one solution is to wrap it in a "div" element.

Let's take a look at whether it works or not!

import React from "react";

const Fragment = () => {
  return (
    <div className="wrapper">
      <p>Fragments</p>
      <p>in React</p>
    </div>
  );
};

export default Fragment;
Enter fullscreen mode Exit fullscreen mode

div wrapper as a solution

Hooray! It worked!

But is this the best solution?

Nah!

There are several problems that come with it.

First of all, we add an extra node to our DOM. It takes extra space in memory.

extra node in the DOM example

Secondly, it's just irrelevant. We need it only for our JSX to work. Kind of ridiculous, right?

And in addition to that, sometimes this div wrapper can even break our layout and lead to invalid HTML to be rendered!

You probably think, how this innocent div can break your HTML?

Let me show you a quick example that will demonstrate that!

Let's imagine that we wanna display a table.
So we define "table", "tbody", "tr" elements.

import Fragment from "./fragment";

function App() {
  return (
    <div className="App">
      <table>
        <tbody>
          <tr>
            <Fragment />
          </tr>
        </tbody>
      </table>
    </div>
  );
}

export default App
Enter fullscreen mode Exit fullscreen mode

And let's say, we want a separate component for our data cells ("td" elements).

import React from "react";

const Fragment = () => {
  return (
    <div className="wrapper">
      <td>Team </td>
      <td>Points</td>
      <td> Wins</td>
    </div>
  );
};

export default Fragment;
Enter fullscreen mode Exit fullscreen mode

We already know that we cannot return multiple values from a component.

Thus we will wrap our "td" elements in a div with class "wrapper" (no styles applied to this class, just for demonstration purposes)

Now let's check if it works or not!

div wrapper cause problems with tables example

Seems like it works but damn...
Look at the console ...

div wrapper cause problems with tables example

We cannot place "td" inside of a div.
And "tr" cannot contain the div element.

Q.E.D.


So, what should we do instead?

You guessed it right - we can use Fragments!

A fragment is just a syntax that allows you to group a list of children (as our div did) but...

Super important, Fragment does not add an extra node to the DOM.

Okay, that sounds like a win-win, right?

How to use it?

Pretty easy !

import React from "react";

const Fragment = () => {
  return (
    <React.Fragment>
      <p>Fragments</p>
      <p>in React</p>
    </React.Fragment>
  );
};

export default Fragment;
Enter fullscreen mode Exit fullscreen mode

All we have to do is use React.Fragment instead of div.

Also, I need to mention that there is another form of React Fragment - short syntax that looks like an empty tag.

import React from "react";

const Fragment = () => {
  return (
    <>
      <p>Fragments</p>
      <p>in React</p>
    </>
  );
};

export default Fragment;
Enter fullscreen mode Exit fullscreen mode

Both of these code examples will result in such DOM:

React Fragment as a solution example

As you can see no additional JSX elements have been added to the DOM!

Is there any difference between React.Fragment and the short syntax?

Actually, there is one small difference

Look at this code snippet:

import React from "react";

const Fragment = () => {
  const arrayOfNumbers = [1, 2, 3, 4, 5];
  return arrayOfNumbers.map((number, index) => (
    <>
      <p>{number}</p>
      <p>{index}</p>
    </>
  ));
};

export default Fragment;
Enter fullscreen mode Exit fullscreen mode

We iterate through the array and for each element return 2 paragraphs (value itself and its index).

We put these paragraphs in an empty tag (short syntax of React.Fragment)

Everything works fine but ...
We got this error in the console ...

Problem with React keys example

If you read my previous post about React keys, you know what it's all about and how to deal with it.
If not, check it out!

I got you bro meme

So, as you understand, we have to add the key to our parent element.

And here is the problem.

We cannot do that with the short syntax of React.Fragment.

Instead, we have to use React.Fragment and give it a key attribute.

import React from "react";

const Fragment = () => {
  const arrayOfNumbers = [1, 2, 3, 4, 5];
  return arrayOfNumbers.map((number, index) => (
    <React.Fragment key={index}>
      <p>{number}</p>
      <p>{index}</p>
    </React.Fragment>
  ));
};

export default Fragment;
Enter fullscreen mode Exit fullscreen mode

Key problem resolved example


Brief conclusion:

Fragments can be used whenever you need to return multiple JSX elements from the component.
You should be using them instead of wrapping everything in a div because React.Fragment does not add an extra node to the DOM. There are 2 forms of it: full and short syntax.
The only difference between them is that you cannot use key attribute (if you need one) with short syntax.


And that's it, guys.

I hope that you have learned something new today!
I would appreciate it if you could like this post or leave a comment below!

Also, feel free to follow me on GitHub and Medium!

Adios, mi amigos)

Baby Yoda saying Goodbye

Top comments (2)

Collapse
 
decryptus007 profile image
Dominic

Wow, thanks for this 👏🏽

Collapse
 
kairatorozobekov profile image
Kairat

I hope you liked it )