eslint-plugin-react
eslint-plugin-react copied to clipboard
react/jsx-no-useless-fragment false positive
There's a false positive on the rule with forwarded children. Use cases are pretty rare but still exist. Without a fragment around the children
, code breaks at runtime
const HollowComponent = ({ children }) => {
// some logic here
return <>{children}</>; // doesn't pass the rule
}
example: https://codesandbox.io/s/icy-lake-ri3uo
Temporary fix is to disable rule for this line but it would be nicer if this rule let this kind of Fragment use possible.
What use cases would require the fragment?
Here are 2 use cases I actually encounter in the project I'm working on.
1. Conditional rendering
Let's say we have a component augmenting its children conditionally like the following:
const Augmenter = ({ children }) => {
// ... logic used here ...
const tempJsx = (
<>
{additionalNodes}
{children}
{otherAdditionalNodes}
</>
)
return renderWithAugmentations
? tempJsx
: <>{children}</>
}
2. Testing hooks (mocks)
const MockComponentUseSomeHook = ({ children }) => {
useSomeHook()
return <>{children}</>
};
In the first case, why wouldn't : children
work identically?
Same question in the second case; return children
should work fine.
As you can see in the codesandbox I pasted in the original post ( https://codesandbox.io/s/suspicious-sunset-ly9ik ), returning the children without a fragment can throw a runtime error (in case no children are provided).
Working with typescript generates an error too as children type for a FunctionalComponent
can be undefined and said functional component cannot return the undefined type.
Thanks for bearing with me.
Type errors aren't relevant, but runtime errors are.
The solution in your code, of course, is to use defaultProps, or const TestEmpty = ({ children = null }) => children;
, so that if it is undefined, it becomes null
, or, const TestEmpty = ({ children }) => children ?? null;
, but it seems reasonable to have an option to specifically allow a prop, only, to be used with an otherwise "unnecessary" fragment, because of undefined
.
Thank you for trying to understand the issue! I'll try the null
workaround in my project which seems reasonable!
Hi, I think I have encountered a similar problem. My use case is like this:
<Query>
{({data, loading}) => {
...
return (
<>
{anArray.map(item => {
return item.success
? getTypeA(item)
: getTypeB(item);
})}
</>
);
}
}
</Query>
This is treated as an error but the render prop expects the return to be a single element so I think the Fragment is necessary here.
I have the same issue where I'm getting an error when there's a single map function inside the fragment. I can't enable this rule and use typescript at once because of this issue.
Same error as zenefits-brody and geoguide.
There's only one child in program's AST, but there may be multiple children in React tree.
https://github.com/yannickcr/eslint-plugin-react/blob/master/lib/rules/jsx-no-useless-fragment.js#L106
One should check if the only child isn't jsx expression with a call expression inside.
Edit: Function call like .map
can also return undefined
so dropping the fragment in this case could result in runtime error.
@ljharb @sbdchd Hi guys, thank you for your work!
Do we have any plan for when [New] jsx-no-useless-fragment: add ignoreUnsafeChildren flag Merge Request is going to be merged?
(merge request is only a gitlab idiom, it's called a "pull request" most commonly)
That PR doesn't match https://github.com/yannickcr/eslint-plugin-react/issues/2584#issuecomment-595978999, so it needs to be updated to do so. If the PR author isn't interested in doing it, anyone else is welcome to comment a link to a branch (please do NOT open a new PR) and i'll update the PR with it.
Had the same issue with conditional rendering did anyone find a solution for that?
My case:
return user ? <>{children}</> : <Navigate to={routes.login.path} />;
Hi, I think I have encountered a similar problem. My use case is like this:
<Query> {({data, loading}) => { ... return ( <> {anArray.map(item => { return item.success ? getTypeA(item) : getTypeB(item); })} </> ); } } </Query>
This is treated as an error but the render prop expects the return to be a single element so I think the Fragment is necessary here.
Was this fixed already? I am still having the issue.
For me the solution was to add allowExpressions
option to the config:
"react/jsx-no-useless-fragment": [2, { allowExpressions: true }]
allowExpressions: true is not work for me