Open davesnx opened 1 week ago
Thanks for reporting. This is due to automatic compiler optimizations. Why is this an issue?
In the issue mentioned, there's a work in progress for reason-react support for React 19.
We use Melange to compile Reason to JavaScript and due the fact that all reason code is curried means that we need to annotate when a function (from the JavaScript world) is uncurried (almost all JavasScript functions are).
If they are annotated with uncurry, we call the code directly since we explicitly tell the compiler to do so.
If we don't, we wrap with a small utility that checks arity (fn.length) and applies their arguments accordingly.
Since the beginning, useState wasn't annotated because functions with arity 1 can't be curried (since they only have 1 argument). Now useState became arity 2, which implies we need to explicitly annotate it as uncurried and implies a breaking change.
This is the why, and I'm aware that's a long explanation that is a bit further from React.js per se, but I opened the issue to understand it better, and I wasn't aware of any automatic optimisations in the react core itself. Can you give me some pointers so that I could understand this better? Maybe there's a way to know what kind of optimisations?
So reason-react can work around this?
but I opened the issue to understand it better, and I wasn't aware of any automatic optimisations in the react core itself. Can you give me some pointers so that I could understand this better? Maybe there's a way to know what kind of optimisations?
We use Closure compiler. We used to only apply this to prod but now do to dev so Closure added another argument to avoid accessing arguments
in https://github.com/facebook/react/blob/6f0dc2947bed21f9be484f37eb32d02fdc4c0481/packages/react-reconciler/src/ReactFiberHooks.js#L3755-L3761
So reason-react can work around this?
I'm going to have a hard time with this. From what I can observe, It might differ from your reply:
The arity on the development version (using ESM.sh) is 1, while the arity of installation via npm (and bundled for prod) is 2.
It's worth mentioning that it's the same with the seducer dispatcher, is that expected as well?
Does the compiler add this to avoid accessing arguments
as a kind-of-a-linter mechanism for React core devs?
From the outside, it seems like a good tradeoff to use another mechanism for it and try not to "break" the arity.
We don't know why Closure does this. This specific optimization was removed in later versions but updating is not trivial: https://github.com/facebook/react/pull/31587
Saw the PR. Thanks for the effort
Summary
The setter from useState becomes arity 2 in React's 19.0.0-rc.1 release.
Haven't found a changelog entry (https://react.dev/blog/2024/04/25/react-19 or https://react.dev/blog/2024/04/25/react-19-upgrade-guide), neither looking at the commits, so I'm not sure if it's intentional or I might miss something here.
Demo
React's 18 setStates is arity 1 https://codesandbox.io/p/sandbox/setstate-arity-1-react-18-pfdr3h React's 19.0.0-rc.1 setState becomes arity 2 https://codesandbox.io/p/sandbox/setstate-arity-2-issue-react-19-x3l3kd