By using React Fragments you can unify child nodes without applying a wrapper DOM element to the component.
Since React Components can return only a single element, you can't do the following:
Instead, the solution is to apply react fragments like so:
React Fragments are used here to group together the other nodes, making it a single element being returned by MyComponent and it doesn't actually render the React.Fragment to the DOM. This pattern avoids a common instinct of wrapping the elements with a `<div>`, which would actually appear on the DOM, while the fragment is simply removed when rendering.
In the above example, list items are being rendered to the DOM and the React.Fragment tag is removed. This is a great utility introduced by the usage of fragments to avoid attaching to the DOM unnecessary nodes such as random divs. And, still considering the example, list items require its parent element to be either a `<ol>`, `<ul>` or `<menu>`, therefore wrapping it in a `<div>` would be an HTML syntax error (More on that here).
Example 1 - Short Syntax
Another way to work with React Fragments is to use its short syntax:
This provides a clear advantage to the developer experience (DX) as it's way easier to type empty open and close tags (<></>) rather than typing `<React.Fragment> </React.Fragment>`.
The drawback of this approach is that it doesn't support the usage of keys or attributes, which may be required in some specific cases.
Example 2 - Applying keys
Although this step requires employing the full syntax, it presents a real benefit as the below example is a common real-world scenario:
Here the component is responsible for rendering a list of header + subheader (h2 and h3) without any wrapper tag. Note that a map method is being executed and just like React components, it expects to return a single element, therefore React.Fragment is applied. The main aspect of this implementation is that each child created by the map method must have a key prop, and only using the full syntax supports it.
Applying a key prop to the mapped elements is how React internally identifies which specific item has gone through changes so that it can update it accordingly when facing those changes. Such an approach can't however, be used with the short syntax for fragments, making it a solid case where the full syntax must be applied instead.
Example 3 - Conditional Rendering
Another common case where React Fragments can be applied is when using conditional rendering. Suppose you wish to render a Header + Subheader combination when some property is set to true and a single `<span>` tag in case it's set to false:
Beware that the React component MyComponent still requires a single element, so we still apply the fragment to wrap the JS ternary expression.
And inside the ternary expression, the case where h2 and h3 will be returned requires wrapping it in a fragment using either the short syntax or the full syntax. In this example, there's no specific need to apply the full one since no key/attribute is required.
To enhance the example a bit, you could also store the desired JSX in a const as such:
This would be especially useful if the 'full header' was composed of a larger amount of elements. In order to make the code more readable, the renderFullHeader function would encapsulate every element it needs, and the return function of MyElement makes it straightforward that it will render the full header or a single span tag depending on the value of a prop.
React Fragments are used to wrap child nodes without attaching an unnecessary element to the DOM. They can be applied using the full syntax, which supports keys and attributes:
or the short syntax, which doesn't support keys and attributes:
The most common case where the full syntax is required is when dealing with cases where a key is required by React so that, internally, it can uniquely identify a given node. An example would be when mapping items from an array to JSX.
If there's no key or attributes set, the short syntax can be applied and both approaches deliver the same result.
The fragments can be applied directly to the return of a React component, inside functions that return JSX, in conditional rendering, and pretty much anywhere else a valid react component can be used.
Besides avoiding adding an unnecessary element to the DOM, fragments are also the solution to not break the rules of the HTML syntax, as in the `<li>` element example where its parent node must be either `<ol>`, `<ul>` or `<menu>`.
Bonus - A look into the internals of React Fragment
By digging into the react codebase we can tell how the React.Fragment component works internally. It is declared using the ExoticComponent TypeScript interface and it specifies a prop `children` which is set to be a ReactNode. The second part makes a lot of sense as the nodes added to the DOM are the children nodes of the fragment component we apply. But what about the ExoticComponent interface, what does it have to do with react fragments?
This declaration allows for developing a special kind of component that would not act as a regular React component. This is exactly the case for React.Fragment. Although it doesn't behave like the other types of components (FunctionComponent is the main one now as StatelessComponent has been deprecated with the introduction of hooks), there's no other way implemented to tell the JSX parser that this is a JSX element type. The way to handle it being a valid JSX element and access its props is by pretending that it is a normal component.
The reason this ExoticComponent interface exists is that a component like React.Fragment should not attach its static methods to the component itself, but to the original function. There's also a 'NamedExoticComponent' interface which includes the displayName (responsible for exhibiting the component name when debugging in React Devtools), but it doesn't make sense to apply it in this context as the fragment serves as a wrapper to its children and will not render any visible UI.
Another example where an ExoticComponent interface is applied is the component React.StrictMode which also doesn't result in attaching a new node to the DOM and is used for debugging purposes while in development mode. You can read more about React's StrictMode in the official docs.