Reanimated error: "Tried to synchronously call a non-worklet function" with React Compiler enabled
Description
Reanimated throws the following error when using useDerivedValue with the latest React Compiler:
[Reanimated] Tried to synchronously call a non-worklet function `_temp` on the UI thread.
This happens because the React Compiler (19.0.0-beta-201e55d-20241215) tries to optimize the code by eagerly extracting functions passed to hooks like useDerivedValue. For example, an inline function:
useDerivedValue(() =>
Object.fromEntries(indexToKey.value.map((key, index) => [key, index]))
);
is transformed into:
t2 = () => Object.fromEntries(indexToKey.value.map(_temp));
Here, _temp is hoisted outside the worklet context, breaking Reanimated’s requirement for worklet functions to remain inline or explicitly marked. This issue did not occur in version 19.0.0-beta-8a03594-20241020, but it is unclear when exactly it was introduced.
You can see the outputted code in React Compiler Playground here.
Steps to reproduce
- Install and enable the latest React Compiler version
19.0.0-beta-201e55d-20241215in your project. - Use Reanimated
useDerivedValuehook with an inline function. - Run the app
Snack or a link to a repository
https://github.com/piotrski/reanimated-compiler-repro
Reanimated version
3.16.1
React Native version
0.76.5
Platforms
iOS
JavaScript runtime
None
Workflow
None
Architecture
None
Build type
None
Device
None
Device model
No response
Acknowledgements
Yes
Hey @piotrski, this PR fixes this: https://github.com/software-mansion/react-native-reanimated/pull/6904
It's available in Reanimated 3.17.1
Could you please check if it works for you?
I have actually confirmed that this is a separate issue with the Compiler, unreleated to #6904
I opened an issue for the React Compiler https://github.com/facebook/react/issues/32580. Given it some thought it's actually impossible to fix it on our end.
Tip for anyone encountering this issue: You can opt out of React Compiler by adding the string literal "use no forget" at the top of your component function body.
I had the issue once this morning,
forcing the local function as a worklet solved the issue on my side but I cannot reproduce it for now :/
Object.fromEntries(indexToKey.value.map((key, index) => {
'worklet'
return [key, index]
}))
Hi, any fixes for this?
@dennis-Softfruit at the moment no. The best workaround for now is to use 'worklet' directives explicitly or add 'use no memo' directive in troublesome components.