Fix "Tried to synchronously call a Remote Function" crash

Capture-free shared value updaters like sv.set(() => withSpring(...))
inside worklets get outlined to module scope by React Compiler. The
outlined function is not workletized, so it is captured into the worklet
closure as a remote function, and set() invoking it synchronously on the
UI runtime crashes fatally (reproduced via the Home pager on Android,
also reachable via DM swipe gestures). Marking the updaters as worklets
keeps them callable on the UI runtime.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Tomek Zawadzki
2026-08-20 14:45:33 +02:00
parent 674f73b813
commit fefc021f5f
5 changed files with 29 additions and 21 deletions
+5 -4
View File
@@ -78,12 +78,13 @@ export function SwipeToReply({
const runPop = () => {
'worklet'
if (isReducedMotion) return
iconScale.set(() =>
withSequence(
iconScale.set(() => {
'worklet'
return withSequence(
withTiming(1.2, {duration: 175}),
withTiming(1, {duration: 100}),
),
)
)
})
}
return (
@@ -63,12 +63,13 @@ export function GestureActionView({
return
}
iconScale.set(() =>
withSequence(
iconScale.set(() => {
'worklet'
return withSequence(
withTiming(1.2, {duration: 175}),
withTiming(1, {duration: 100}),
),
)
)
})
}
useAnimatedReaction(
@@ -205,7 +206,10 @@ export function GestureActionView({
scheduleOnRN(actions.rightFirst.action)
}
}
transX.set(() => withTiming(0, {duration: 200}))
transX.set(() => {
'worklet'
return withTiming(0, {duration: 200})
})
hitFirst.set(false)
hitSecond.set(false)
isActive.set(false)
+5 -4
View File
@@ -33,12 +33,13 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
const setModeWorklet = useCallback(
(v: boolean) => {
'worklet'
footerMode.set(() =>
withSpring(v ? 1 : 0, {
footerMode.set(() => {
'worklet'
return withSpring(v ? 1 : 0, {
...Reanimated3DefaultSpringConfig,
overshootClamping: true,
}),
)
})
})
},
[footerMode],
)
+5 -4
View File
@@ -104,12 +104,13 @@ export function MainScrollProvider({children}: {children: React.ReactNode}) {
const setMode = useCallback(
(v: boolean) => {
'worklet'
headerMode.set(() =>
withSpring(v ? 1 : 0, {
headerMode.set(() => {
'worklet'
return withSpring(v ? 1 : 0, {
...Reanimated3DefaultSpringConfig,
overshootClamping: true,
}),
)
})
})
},
[headerMode],
)
+5 -4
View File
@@ -150,12 +150,13 @@ function HomeScreenReady({
const headerMode = useHomeHeaderMode()
const showHeader = useCallback(() => {
'worklet'
headerMode.set(() =>
withSpring(0, {
headerMode.set(() => {
'worklet'
return withSpring(0, {
...Reanimated3DefaultSpringConfig,
overshootClamping: true,
}),
)
})
})
}, [headerMode])
useFocusEffect(