It’s is a common practice in React to render dynamically multiple sibling components. When returning JSX from a React component we need to maintain the tree structure of the HTML elements. The component must return at most 1 top-level node. Fragments let us deal with this problem in a very effective way.
The problem
Let’s start by understanding the problem that Fragments are meant to solve.
function App() {
return (
<div>
<ul>
<Users />
</ul>
</div>
);
}
export default App;
const Users = () => {
return (
<li>Tommy</li>
<li>Mike</li>
<li>Anna</li>
)
}
This piece of code has an error that lies in the Users component.
As you can see even our IDE is complaining that ‘JSX expressions must have one parent element’. We’re trying to return three elements with no parent, hence the code won’t compile. We need to wrap those elements with something. Let’s use div for now.
The solution
function App() {
return (
<div>
<ul>
<Users />
</ul>
</div>
);
}
export default App;
const Users = () => {
return (
<div>
<li>Tommy</li>
<li>Mike</li>
<li>Anna</li>
</div>
)
}
Now the error went away and everything is seemingly fine, but let’s take a look at the DOM structure of our application. Do you see something strange?
That’s right the li elements are wrapped with that extra div element that we were forced to add. Instead of using div, we can use the Fragment.
React Fragment
import React from "react";
function App() {
return (
<div>
<ul>
<Users />
</ul>
</div>
);
}
export default App;
const Users = () => {
return (
<React.Fragment>
<li>Tommy</li>
<li>Mike</li>
<li>Anna</li>
</React.Fragment>
)
}
Let’s check out the DOM structure again to see if the problem went away.
Can you spot the difference? That’s right. Fragments let us wrap nodes without rendering extra element to the DOM. It’s a pretty convenient tool.
Short syntax
You can use a short syntax for most of the use cases. You can use it in the same way you would use any other element.
Instead of using <React.Fragment>…</React.Fragment>, we can simply use <>…</>
import React from "react";
function App() {
return (
<div>
<ul>
<Users />
</ul>
</div>
);
}
export default App;
const Users = () => {
return (
<>
<li>Tommy</li>
<li>Mike</li>
<li>Anna</li>
</>
)
}
One important thing to note here is that the short syntax doesn’t support passing attributes to it. In some cases, you may wanna pass a key property to the parent level element. This usually happens when using JS map()
import React from "react";
const USERS = [{ name: 'Tommy', age: 16 }, { name: 'Mike', age: 54 } , { name: 'Anna', age: 21 }]
function App() {
return (
<dl>
{USERS.map((user, index) => (
<React.Fragment key={index}>
<dt>{user.name}</dt>
<dd>{user.age}</dd>
</React.Fragment>
))}
</dl>
);
}
export default App;
Personally, I find using Fragments very helpful. Try to use them yourself whenever possible. It’s a good practice.
💬 Leave a comment