[React 19] Using spread with binary conditional in JSX causes error in dev env for case of using legacy JSX transform
Summary
Prerequisites
- React app which compiles with legacy JSX transform
- Add a JSX element with spread operator with binary conditional, e.g.:
<button
{...(isCountButtonActive && {
onClick: () => setCount(currentCount => currentCount + 1)
})}
>
Increment count
</button>
- Run app in dev mode
Result
Error is thrown when conditional is evaluated to false:
Uncaught TypeError: Cannot use 'in' operator to search for '__self' in false
at exports.createElement (chunk-Y64RAOT6.js?v=f4a3421f:775:86)
at App (App.jsx:3:13)
at callComponentInDEV (react-dom_client.js?v=f4a3421f:785:18)
at renderWithHooks (react-dom_client.js?v=f4a3421f:3510:24)
at updateFunctionComponent (react-dom_client.js?v=f4a3421f:4521:21)
at beginWork (react-dom_client.js?v=f4a3421f:5096:20)
at runWithFiberInDEV (react-dom_client.js?v=f4a3421f:864:18)
at performUnitOfWork (react-dom_client.js?v=f4a3421f:7688:83)
at workLoopSync (react-dom_client.js?v=f4a3421f:7580:43)
at renderRootSync (react-dom_client.js?v=f4a3421f:7561:13)
Code fragment where it's thrown:
if (null != config) for (propName in didWarnAboutOldJSXRuntime || !("__self" in config) || "key" in config || (didWarnAboutOldJSXRuntime = true, warn("Your app (or one of its dependencies) is using an outdated JSX transform. Update to the modern JSX transform for faster performance: https://react.dev/link/new-jsx-transform")), hasValidRef(config), hasValidKey(config) && (checkKeyStringCoercion(config.key), typeString = "" + config.key), config) hasOwnProperty.call(config, propName) && "key" !== propName && "__self" !== propName && "__source" !== propName && (i[propName] = config[propName]);
Reproduction
https://github.com/undeletable/jsx-spread-with-react-19-rc Click 'Toggle count button state' to reproduce
I think the "modern" way to do is to conditionally assign the event handler directly within the onClick, like for example:
<button
onClick={isCountButtonActive ? () => setCount(currentCount => currentCount + 1) : undefined}
>
Increment count
</button>
@saul-atomrigs Thanks. I know several ways to work that around, including your approach. But the code in my example should work too, as it's valid and spread operator usage too, and not less 'modern' one for sure. That's why I've raised the issue.
I'm going to work on the fix
This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!
Still an issue. Upgraded to the latest RC in repository with reproduce.
There's PR with fix: https://github.com/facebook/react/pull/29925 Updated it with the latest changes from main branch
This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!
Still an issue in 19.0.0
bump
This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!
Still an issue with React 19.1.0
This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!
Still an issue with React 19.1.1
Is there any progress with it? The code is full of this syntax, and without this fix I cannot upgrade to v19.
@nirapx I've got PR https://github.com/facebook/react/pull/29925 fixing this, but still it's awaiting review