In this blog post we are going to explore how to return multiple elements from a component's render
(for class-based) or return
(for functional) methods.
What elements are returned?
Let's refresh in the memory what elements are returned - those are React elements, which have been converted from HTML tags by JSX (JavaScript XML). JSX allows us to write HTML elements in JavaScript and place them in the DOM without any createElement()
and/or appendChild()
methods.
Example:
return() {
<div>
<h1>Hello World!</h1>
</div>
}
But we also know that "under the hood" there is Babel compiler, which transforms JSX into React.createElement()
function:
return() {
React.createElement('div', {}, [
React.createElement('h1', {}, 'Hello World!')
]);
}
So, as you can see, React.createElement
can accept only one type of element (in our case it's div
and h1
) as first parameter. That is why when you return JSX from a function or statement, you must return a single element (with children or without).
In our example it is div
which is single or top element for JSX.
Multiple elements
What if we want to return multiple elements and we don't need that div
container?
Let's explore the following example:
const Table = () => {
return (
<table>
<tr>
<Columns />
</tr>
</table>
);
}
The component <Columns />
in its turn is rendering a couple of columns:
const Columns = () => {
return (
<div>
<td>Column 1</td>
<td>Column 2</td>
</div>
);
}
As a result of the code above, we are getting invalid HTML from <Table />
component on the page:
<table>
<tr>
<div>
<td>Column 1</td>
<td>Column 2</td>
</div>
</tr>
</table>
Solution?
This problem can be solved in 2 ways:
1./ By using Aux Component (Auxiliary) or HOC
2./ By using React.Fragment component
Let's examine both of ways.
Aux (Auxiliary) Components or HOC
A higher-order component (HOC) in React is a pattern used to share common functionality between components without repeating code. HOC is actually not a component though, it is a function. A HOC function takes a component as an argument and returns a component. It transforms a component into another component and adds additional data or functionality.
In short:
const NewComponent = (BaseComponent) => {
// ... create new component from old one and update
return UpdatedComponent
}
HOC can be used as a container for another component (in this case it's often called auxiliary component or Aux in the project). In this case it simply takes props
as argument and returns children
:
const Aux = (props) => props.children;
export default Aux;
In our example we can simply change wrapper div
with Aux
:
const Columns = () => {
return (
<Aux>
<td>Column 1</td>
<td>Column 2</td>
</Aux>
);
}
And problem solved!
React.Fragment
React.Fragment was introduced in React 16.2.0.
React.Fragment
let you group a list of children without adding extra nodes to the DOM because fragments are not rendered to the DOM. So basically we use React.Fragment where we would normally use a wrapper div
.
In our example we can simply change wrapper div
with React.Fragment
:
const Columns = () => {
return (
<React.Fragment>
<td>Column 1</td>
<td>Column 2</td>
</React.Fragment>
);
}
OR fragments can also be declared with a short syntax which looks like an empty tag:
const Columns = () => {
return (
<>
<td>Column 1</td>
<td>Column 2</td>
</>
);
}
And problem solved!
Conclusion:
- It's possible to use both variants since they do the same job - allow to return multiple JSX elements without adding extra layer
- Using
React.Fragment
has more benefits though, since you don't need to create extra component and it’s a tiny bit faster and has less memory usage (no need to create an extra DOM node).
Thank you for reading my blog and thank you for your comments :)
Top comments (8)
Can you explain "no need to create an extra DOM node"? I don't see any additional DOM nodes in the HOC version.
I meant extra node not in HOC, but in general, if we create wrapper div it is extra DOM node.
Ahh I see, makes sense, thanks for the clarification!
Nice article, actually never thought of using an HOC only for this usecase. Of course, fragments are better but it's nice to have also the HOC perspective.
It is really amazing how flexible React is :)
That Aux component pattern is really interesting. I had never seen or thought of that.
As a newbie, I've seen HOCs for that, but the default way (React.fragment) is surely the best way to go: built-in, faster, no need to hack it
Yep :) but knowing another way doesn’t hurt :)