Tried to synchronously call function {parseISO} from a different thread - but it's marked as a worklet?
See original GitHub issueDescription
Marking function as worklet but it still tries to call it on the JS thread
Expected behavior
It will run on the UI thread
Actual behavior & steps to reproduce
Try out the snack (will not show logs or the error)
or pull down the example repo try it locally (will show logs and error)
Snack or minimal code example
https://github.com/Norfeldt/worklet-example/blob/main/App.tsx
https://snack.expo.dev/@nord_investments/worklet-example
import React, { useEffect } from 'react';
import { StyleSheet, View, Text } from 'react-native';
import Animated, {
useSharedValue,
useAnimatedStyle,
withSpring,
withRepeat,
useAnimatedGestureHandler,
} from 'react-native-reanimated';
import {
Gesture,
GestureDetector,
GestureHandlerRootView,
} from 'react-native-gesture-handler';
import { ReText } from 'react-native-redash';
import { format, parseISO } from 'date-fns'
const someWorklet = (year: string, displayFormat = 'dd.MM.yyyy') => {
'worklet';
console.log('worklet log');
const formattedDate = format(parseISO(`${year}-01-01`), displayFormat);
return formattedDate;
};
export default function App() {
const year = useSharedValue('2022');
const randomDate = useSharedValue('N/A');
const tapGesture = Gesture.Tap().onStart(() => {
console.log('getsture logging');
randomDate.value = someWorklet(year.value);
});
return (
<View style={styles.container}>
<GestureHandlerRootView style={styles.gestureArea}>
<GestureDetector gesture={tapGesture} style={styles.gestureArea}>
<Animated.View style={styles.gestureArea}>
<Text>Static Text</Text>
<ReText text={randomDate} style={styles.text} />
</Animated.View>
</GestureDetector>
</GestureHandlerRootView>
</View>
);
}
Package versions
name | version |
---|---|
react-native | 0.64.3 |
react-native-reanimated | ~2.3.1 |
NodeJS | v16.15.1 |
Xcode | N/A |
Java | N/A |
Gradle | N/A |
expo | 44 |
package.json
{ “main”: “node_modules/expo/AppEntry.js”, “scripts”: { “start”: “expo start”, “android”: “expo start --android”, “ios”: “expo start --ios”, “web”: “expo start --web”, “eject”: “expo eject” }, “dependencies”: { “expo”: “~44.0.0”, “expo-status-bar”: “~1.2.0”, “react”: “17.0.1”, “react-dom”: “17.0.1”, “react-native”: “0.64.3”, “react-native-web”: “0.17.1”, “react-native-paper”: “4.9.2”, “@expo/vector-icons”: “^12.0.0”, “expo-constants”: “~13.0.2”, “react-native-reanimated”: “~2.3.1”, “react-native-screens”: “~3.10.1”, “react-native-gesture-handler”: “~2.1.0”, “date-fns”: “^2.28.0”, “react-native-redash”: “^18.0.0” }, “devDependencies”: { “@babel/core”: “^7.12.9”, “@types/react”: “~17.0.21”, “@types/react-native”: “~0.64.12”, “typescript”: “~4.3.5” }, “private”: true, “resolutions”: { “@types/react”: “~17.0.47” } }
Affected platforms
- Android
- [ x] iOS
- Web
Issue Analytics
- State:
- Created a year ago
- Comments:7 (7 by maintainers)
Thank you very much for this great clarification - it’s a great help to me.
Shared values are completely independent from React, component life cycle, virtual DOM etc. Basically, shared value is just some JS value (number, string, array or object) that you can read and update from both JS contexts, i.e. from RN code and from worklets. In worklets, reading and writing to shared value is synchronous. In regular RN JS code, reading shared value is synchronous (but the result can be outdated) and writing to shared value is asynchronous (i.e. scheduled on the UI thread). Shared values can be used to share some data between these two JS contexts, like width, height or color of some component, and can also be smoothly and precisely animated using
withTiming
,withSpring
etc.The workaround I have suggested only makes sense when the “update” originates from the main JS context (e.g. after RN component state change, when some network request completes, etc.). In cases when the event originates from the UI thread (i.e. when using Gesture Handler), we would like to handle it on the UI thread so the app feels responsive. Otherwise, we would block the UI thread until JS context completes our function call.
In the specific case of showing different dates depending on pan gesture scroll, I would recommend implementing the formatting function as a worklet on your own.