Stop using React.Fragment
Learn how a simple tweak to React's Fragment component can streamline your code and reduce mental overhead. It's a small change with a big impact on cleaner code and easier debugging—just be mindful of a few caveats. Curious how it works? Dive in and simplify your React workflow!
React apps are so common these days that if you have not heard of it as a front end developer; it is safe to assume that you are living under a rock.
React is a well known UI library these days and it is safe to assume its presence as next jQuery (even though it will never reach the same popularity) One of the commonly used term in the react world is Fragment which is similar to DOM fragment.
My argument is that you should stop using the Fragment component provided by React.
Ok, that was misleading (and sorry for the click bait title); what I am suggesting is not a direct use but a proxied use. Proxied use where we will add few modifications on React.Fragment
and export the new fragment.
When to use Fragment
JSX is an XML compliant syntax and it has some rules. One of the rules says that a components return/render can not have multiple root nodes unless they hay key prop. So Not allowed:
return (
<span>Hello</span>
<span>World</span>
)
But it is fine to either wrap it with another node or give keys to both spans
return (
<div>
<span>Hello</span>
<span>World</span>
</div>
)
OR
return [
<span key="hello">Hello</span>,
<span key="world">World</span>
]
We often went with first option to wrap the output of multiple nodes with one node (usually div
)
But this created a problem of littering the browser DOM with useless divs.
We could have gone with second option and not need the wrapping but it is neither practical non optimal for the developer productivity. For example, the above components with some arbitrary text. Keys are vague and not data driven. That means, there will be no rules on how to approach the key naming. we could leave it to some external lib but it is extra overhead for trivial needs. And data based outputs are already using keys.
Getting back to usage of wrapper node, as I said, littering of DOM with useless nodes poses debugging & styling issues .
To solve this React team came up with Fragments. The idea is similar to DOM fragments where a simple fragment can hold any number of random nodes and this fragment can be attached or moved around in the functional context
const footer = document.createFragment();
const btnCTA = document.createElement("button");
btnCTA.id = "subscribe";
btnCTA.classList.add("bin", "btn-primary");
const btnReset = document.createElement("button");
btnReset.id = "reset";
btnReset.classList.add("btn", "bin-outline");
footer.appendChild(btnCTA);
footer.appendChild(btnReset);
// Now we can return this fragment
// or append it to any desired place
React fragment is similar and only accepts one prop, 'key', for the instances when you are returning multiple fragments
return (
<React.Fragment>
<span>Hello</span>
<span>World</span>
</React.Fragment>
)
Why not to use fragment via adapter
Consider the following example where we want to conditionally add a container to our component
Here the problem will occur if as
prop is passed as null
and that will cause the Comp
to be React's fragment. And when it is fragment you can not pass other than 'key'
This restriction will cause the creation of another conditional variable. This conditional variable is gonna be about the props that can be passed to Comp
.
Solution
What if fragment could just ignore the needless props.
I know that the explicit intent is much better but just for being explicit, we are forced to keep few more conditionals and the one part of those conditional doesn't even know/care about our awesome explicitly written set of props.
Consider the following proxied Fragment
import {Fragment as ReactFragment} from "react";
type Props = Record<string, any>;
export const Fragment = (props: Props) => {
const {key, children} = props;
return (
<ReactFragment key={key}>{children}</ReactFragment>
)
}:
Now that this proxied fragment picks up only needed props and ignores rest, it is not going to clutter your browser console and you dont need to make conditional prop passing.
Things to remember
- We silenced the internal mechanism to scream about unnecessary props, so we need to be extra careful when debugging
- TypeScript usage is tricky (as you can see it in the CodeSandbox)
- And 👇
Conclusion
Seems like a small use case but such small things take up lot of mental space. This small proxied Fragment cleans up the code in upper lever components.
But use it with caution, this is an abstraction and anyone using this should always keep in mind why are we using it, in case things go south 😅
Let me know you through and comments? or on Twitter at @heypankaj_ and/or @time2hack
If you find this article helpful, please share it with others.
Subscribe to the blog to receive new posts right to your inbox.