DEV Community

loading...
Cover image for Aux Component vs React Fragment  - which one is better?

Aux Component vs React Fragment - which one is better?

olenadrugalya profile image Olena Drugalya Updated on ・3 min read

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>
}
Enter fullscreen mode Exit fullscreen mode

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!')
]);
}
Enter fullscreen mode Exit fullscreen mode

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>
    );
}
Enter fullscreen mode Exit fullscreen mode

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>
    );
  }
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

In our example we can simply change wrapper div with Aux:

const Columns = () => {
    return (
      <Aux>
        <td>Column 1</td>
        <td>Column 2</td>
      </Aux>
    );
  }
Enter fullscreen mode Exit fullscreen mode

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>
    );
  }
Enter fullscreen mode Exit fullscreen mode

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>
      </>
    );
  }
Enter fullscreen mode Exit fullscreen mode

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 :)

Buy Me a Coffee at ko-fi.com

Discussion (8)

pic
Editor guide
Collapse
lionelrowe profile image
lionel-rowe

Can you explain "no need to create an extra DOM node"? I don't see any additional DOM nodes in the HOC version.

Collapse
olenadrugalya profile image
Olena Drugalya Author

I meant extra node not in HOC, but in general, if we create wrapper div it is extra DOM node.

Collapse
lionelrowe profile image
lionel-rowe

Ahh I see, makes sense, thanks for the clarification!

Collapse
alexandrudanpop profile image
Alexandru-Dan Pop

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.

Collapse
olenadrugalya profile image
Olena Drugalya Author

It is really amazing how flexible React is :)

Collapse
tylerlwsmith profile image
Tyler Smith

That Aux component pattern is really interesting. I had never seen or thought of that.

Collapse
alaindet profile image
Alain D'Ettorre

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

Collapse
olenadrugalya profile image
Olena Drugalya Author

Yep :) but knowing another way doesn’t hurt :)