Migrate runOnUI/runOnJS to scheduleOnUI/scheduleOnRN (#11249)
This commit is contained in:
@@ -30,7 +30,6 @@ import {KeyboardEvents} from 'react-native-keyboard-controller'
|
||||
import Animated, {
|
||||
clamp,
|
||||
interpolate,
|
||||
runOnJS,
|
||||
type SharedValue,
|
||||
useAnimatedReaction,
|
||||
useAnimatedStyle,
|
||||
@@ -44,6 +43,7 @@ import {
|
||||
useSafeAreaInsets,
|
||||
} from 'react-native-safe-area-context'
|
||||
import {captureRef} from 'react-native-view-shot'
|
||||
import {scheduleOnRN} from 'react-native-worklets'
|
||||
import {Image, type ImageErrorEventData} from 'expo-image'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
@@ -166,7 +166,7 @@ export function Root({children}: {children: React.ReactNode}) {
|
||||
// note: return location has to be reset on open,
|
||||
// rather than on close, otherwise there's a flicker
|
||||
// where the reanimated update is faster than the react render
|
||||
runOnJS(onCompletedClose)()
|
||||
scheduleOnRN(onCompletedClose)
|
||||
}
|
||||
}),
|
||||
)
|
||||
@@ -331,7 +331,7 @@ export function Trigger({
|
||||
() => hoveredItemSV.get(),
|
||||
(hovered, prev) => {
|
||||
if (hovered !== prev) {
|
||||
runOnJS(setHoveredMenuItem)(hovered)
|
||||
scheduleOnRN(setHoveredMenuItem, hovered)
|
||||
}
|
||||
},
|
||||
)
|
||||
@@ -343,7 +343,7 @@ export function Trigger({
|
||||
.averageTouches(true)
|
||||
.onStart(() => {
|
||||
'worklet'
|
||||
runOnJS(open)('full')
|
||||
scheduleOnRN(open, 'full')
|
||||
})
|
||||
.onUpdate(evt => {
|
||||
'worklet'
|
||||
@@ -357,7 +357,7 @@ export function Trigger({
|
||||
// as the menu may have slid into place beneath their finger
|
||||
const item = hoveredItemSV.get()
|
||||
if (item) {
|
||||
runOnJS(onTouchUpMenuItem)(item)
|
||||
scheduleOnRN(onTouchUpMenuItem, item)
|
||||
}
|
||||
})
|
||||
}, [open, hoverablesSV, onTouchUpMenuItem, hoveredItemSV, translationSV])
|
||||
|
||||
@@ -21,11 +21,11 @@ import {
|
||||
} from 'react-native'
|
||||
import {useReanimatedKeyboardAnimation} from 'react-native-keyboard-controller'
|
||||
import Animated, {
|
||||
runOnJS,
|
||||
type ScrollEvent,
|
||||
useAnimatedStyle,
|
||||
} from 'react-native-reanimated'
|
||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||
import {scheduleOnRN} from 'react-native-worklets'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
@@ -299,9 +299,9 @@ export const InnerFlatList = forwardRef<
|
||||
}
|
||||
const {contentOffset} = e
|
||||
if (contentOffset.y > 0 && !disableDrag) {
|
||||
runOnJS(setDisableDrag)(true)
|
||||
scheduleOnRN(setDisableDrag, true)
|
||||
} else if (contentOffset.y <= 1 && disableDrag) {
|
||||
runOnJS(setDisableDrag)(false)
|
||||
scheduleOnRN(setDisableDrag, false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import Animated, {
|
||||
type AnimatedRef,
|
||||
measure,
|
||||
Reanimated3DefaultSpringConfig,
|
||||
runOnJS,
|
||||
scrollTo,
|
||||
type SharedValue,
|
||||
useAnimatedRef,
|
||||
@@ -14,6 +13,7 @@ import Animated, {
|
||||
withSpring,
|
||||
withTiming,
|
||||
} from 'react-native-reanimated'
|
||||
import {scheduleOnRN} from 'react-native-worklets'
|
||||
|
||||
import {useHaptics} from '#/lib/haptics'
|
||||
import {atoms as a, useTheme, web} from '#/alf'
|
||||
@@ -26,7 +26,7 @@ import {IS_IOS} from '#/env'
|
||||
*
|
||||
* All positioning is driven by a `slots` map (key → index) and translateY
|
||||
* (no discrete `top` changes). On drag end the new slot assignment is
|
||||
* computed on the UI thread first, then React state is updated via runOnJS.
|
||||
* computed on the UI thread first, then React state is updated via scheduleOnRN.
|
||||
*
|
||||
* See SortableList.web.tsx for the web implementation using pointer events.
|
||||
*/
|
||||
@@ -265,9 +265,9 @@ function SortableItem<T>({
|
||||
measureDone.set(false)
|
||||
lastHapticSlot.set(mySlot)
|
||||
if (onDragStart) {
|
||||
runOnJS(onDragStart)()
|
||||
scheduleOnRN(onDragStart)
|
||||
}
|
||||
runOnJS(playHaptic)()
|
||||
scheduleOnRN(playHaptic)
|
||||
})
|
||||
.onChange(e => {
|
||||
'worklet'
|
||||
@@ -285,7 +285,7 @@ function SortableItem<T>({
|
||||
const clampedSlot = Math.max(0, Math.min(currentSlot, itemCount - 1))
|
||||
if (IS_IOS && clampedSlot !== lastHapticSlot.get()) {
|
||||
lastHapticSlot.set(clampedSlot)
|
||||
runOnJS(playHaptic)('Light')
|
||||
scheduleOnRN(playHaptic, 'Light')
|
||||
}
|
||||
})
|
||||
.onEnd(() => {
|
||||
@@ -326,13 +326,13 @@ function SortableItem<T>({
|
||||
dragStartSlot: -1,
|
||||
})
|
||||
dragY.set(0)
|
||||
runOnJS(onCommitReorder)(sorted)
|
||||
scheduleOnRN(onCommitReorder, sorted)
|
||||
} else {
|
||||
const s = state.get()
|
||||
state.set({...s, activeKey: '', dragStartSlot: -1})
|
||||
dragY.set(0)
|
||||
if (onDragEnd) {
|
||||
runOnJS(onDragEnd)()
|
||||
scheduleOnRN(onDragEnd)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -347,7 +347,7 @@ function SortableItem<T>({
|
||||
const s = state.get()
|
||||
state.set({...s, activeKey: '', dragStartSlot: -1})
|
||||
if (onDragEnd) {
|
||||
runOnJS(onDragEnd)()
|
||||
scheduleOnRN(onDragEnd)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -2,12 +2,12 @@ import {useRef, useState} from 'react'
|
||||
import {Modal, Pressable, StyleSheet, View} from 'react-native'
|
||||
import Animated, {
|
||||
interpolate,
|
||||
runOnJS,
|
||||
useAnimatedStyle,
|
||||
useSharedValue,
|
||||
withSpring,
|
||||
withTiming,
|
||||
} from 'react-native-reanimated'
|
||||
import {scheduleOnRN} from 'react-native-worklets'
|
||||
import {useLingui} from '@lingui/react/macro'
|
||||
|
||||
import {atoms as a} from '#/alf'
|
||||
@@ -52,7 +52,7 @@ export function ImageMenu({onPressShare, onPressSave}: Props) {
|
||||
progress.set(
|
||||
withTiming(0, TIMING_OUT, finished => {
|
||||
if (finished) {
|
||||
runOnJS(setIsMounted)(false)
|
||||
scheduleOnRN(setIsMounted, false)
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
import Animated, {
|
||||
type AnimatableValue,
|
||||
Reanimated3DefaultSpringConfig,
|
||||
runOnJS,
|
||||
type SharedValue,
|
||||
useAnimatedReaction,
|
||||
useAnimatedRef,
|
||||
@@ -16,6 +15,7 @@ import Animated, {
|
||||
useSharedValue,
|
||||
withSpring,
|
||||
} from 'react-native-reanimated'
|
||||
import {scheduleOnRN} from 'react-native-worklets'
|
||||
import {Image} from 'expo-image'
|
||||
|
||||
import {
|
||||
@@ -95,7 +95,7 @@ const ImageItem = ({
|
||||
},
|
||||
(nextIsScaled, prevIsScaled) => {
|
||||
if (nextIsScaled !== prevIsScaled) {
|
||||
runOnJS(handleZoom)(nextIsScaled)
|
||||
scheduleOnRN(handleZoom, nextIsScaled)
|
||||
}
|
||||
},
|
||||
)
|
||||
@@ -245,7 +245,7 @@ const ImageItem = ({
|
||||
|
||||
const singleTap = Gesture.Tap().onEnd(() => {
|
||||
'worklet'
|
||||
runOnJS(onTap)()
|
||||
scheduleOnRN(onTap)
|
||||
})
|
||||
|
||||
const doubleTap = Gesture.Tap()
|
||||
@@ -359,9 +359,9 @@ const ImageItem = ({
|
||||
},
|
||||
(show, prevShow) => {
|
||||
if (!prevShow && show) {
|
||||
runOnJS(setShowLoader)(true)
|
||||
scheduleOnRN(setShowLoader, true)
|
||||
} else if (prevShow && !show) {
|
||||
runOnJS(setShowLoader)(false)
|
||||
scheduleOnRN(setShowLoader, false)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
@@ -14,7 +14,6 @@ import {
|
||||
type PanGesture,
|
||||
} from 'react-native-gesture-handler'
|
||||
import Animated, {
|
||||
runOnJS,
|
||||
type SharedValue,
|
||||
useAnimatedProps,
|
||||
useAnimatedReaction,
|
||||
@@ -24,6 +23,7 @@ import Animated, {
|
||||
useSharedValue,
|
||||
} from 'react-native-reanimated'
|
||||
import {useSafeAreaFrame} from 'react-native-safe-area-context'
|
||||
import {scheduleOnRN} from 'react-native-worklets'
|
||||
import {Image} from 'expo-image'
|
||||
|
||||
import {
|
||||
@@ -84,7 +84,7 @@ const ImageItem = ({
|
||||
'worklet'
|
||||
const nextIsScaled = e.zoomScale > 1
|
||||
if (scaled !== nextIsScaled) {
|
||||
runOnJS(handleZoom)(nextIsScaled)
|
||||
scheduleOnRN(handleZoom, nextIsScaled)
|
||||
}
|
||||
},
|
||||
onBeginDrag() {
|
||||
@@ -118,7 +118,7 @@ const ImageItem = ({
|
||||
|
||||
const singleTap = Gesture.Tap().onEnd(() => {
|
||||
'worklet'
|
||||
runOnJS(onTap)()
|
||||
scheduleOnRN(onTap)
|
||||
})
|
||||
|
||||
const doubleTap = Gesture.Tap()
|
||||
@@ -142,7 +142,7 @@ const ImageItem = ({
|
||||
screenSize,
|
||||
)
|
||||
}
|
||||
runOnJS(zoomTo)(nextZoomRect)
|
||||
scheduleOnRN(zoomTo, nextZoomRect)
|
||||
})
|
||||
|
||||
const composedGesture = Gesture.Exclusive(
|
||||
@@ -199,9 +199,9 @@ const ImageItem = ({
|
||||
},
|
||||
(show, prevShow) => {
|
||||
if (!prevShow && show) {
|
||||
runOnJS(setShowLoader)(true)
|
||||
scheduleOnRN(setShowLoader, true)
|
||||
} else if (prevShow && !show) {
|
||||
runOnJS(setShowLoader)(false)
|
||||
scheduleOnRN(setShowLoader, false)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
@@ -20,8 +20,6 @@ import Animated, {
|
||||
measure,
|
||||
type MeasuredDimensions,
|
||||
ReduceMotion,
|
||||
runOnJS,
|
||||
runOnUI,
|
||||
type SharedValue,
|
||||
useAnimatedReaction,
|
||||
useAnimatedRef,
|
||||
@@ -32,6 +30,7 @@ import Animated, {
|
||||
withSpring,
|
||||
type WithSpringConfig,
|
||||
} from 'react-native-reanimated'
|
||||
import {scheduleOnRN, scheduleOnUI} from 'react-native-worklets'
|
||||
import {Image} from 'expo-image'
|
||||
import * as ScreenOrientation from 'expo-screen-orientation'
|
||||
|
||||
@@ -136,10 +135,10 @@ export default function ImageViewRoot({
|
||||
|
||||
const onFullyClosed = useCallback(() => {
|
||||
setActiveLightbox(null)
|
||||
runOnUI(() => {
|
||||
scheduleOnUI(() => {
|
||||
'worklet'
|
||||
thumbRects.set({})
|
||||
})()
|
||||
})
|
||||
requestIdleCallback(() => {
|
||||
void Image.clearMemoryCache()
|
||||
})
|
||||
@@ -149,7 +148,7 @@ export default function ImageViewRoot({
|
||||
() => openProgress.get() === 0,
|
||||
(isGone, wasGone) => {
|
||||
if (isGone && !wasGone) {
|
||||
runOnJS(onFullyClosed)()
|
||||
scheduleOnRN(onFullyClosed)
|
||||
}
|
||||
},
|
||||
)
|
||||
@@ -160,10 +159,10 @@ export default function ImageViewRoot({
|
||||
() => openProgress.get() === 1,
|
||||
(isOpen, wasOpen) => {
|
||||
if (isOpen && !wasOpen) {
|
||||
runOnJS(ScreenOrientation.unlockAsync)()
|
||||
scheduleOnRN(ScreenOrientation.unlockAsync)
|
||||
} else if (!isOpen && wasOpen) {
|
||||
// default is PORTRAIT_UP - set via config plugin in app.config.js -sfn
|
||||
runOnJS(ScreenOrientation.lockAsync)(PORTRAIT_UP)
|
||||
scheduleOnRN(ScreenOrientation.lockAsync, PORTRAIT_UP)
|
||||
}
|
||||
},
|
||||
)
|
||||
@@ -171,7 +170,7 @@ export default function ImageViewRoot({
|
||||
const onFlyAway = useCallback(() => {
|
||||
'worklet'
|
||||
openProgress.set(0)
|
||||
runOnJS(onRequestClose)()
|
||||
scheduleOnRN(onRequestClose)
|
||||
}, [onRequestClose, openProgress])
|
||||
|
||||
return (
|
||||
@@ -320,7 +319,7 @@ function ImageView({
|
||||
const handleRequestClose = useCallback(() => {
|
||||
const activeRef = images[imageIndex]?.thumbRef
|
||||
if (isAnimated && activeRef) {
|
||||
runOnUI(() => {
|
||||
scheduleOnUI(() => {
|
||||
'worklet'
|
||||
const rect = measure(activeRef)
|
||||
thumbRects.modify(rects => {
|
||||
@@ -328,8 +327,8 @@ function ImageView({
|
||||
rects[imageIndex] = rect
|
||||
return rects
|
||||
})
|
||||
runOnJS(onRequestClose)()
|
||||
})()
|
||||
scheduleOnRN(onRequestClose)
|
||||
})
|
||||
} else {
|
||||
onRequestClose()
|
||||
}
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import {createContext, useContext, useEffect, useMemo, useState} from 'react'
|
||||
import {
|
||||
measure,
|
||||
type MeasuredDimensions,
|
||||
runOnJS,
|
||||
runOnUI,
|
||||
} from 'react-native-reanimated'
|
||||
import {measure, type MeasuredDimensions} from 'react-native-reanimated'
|
||||
import {scheduleOnRN, scheduleOnUI} from 'react-native-worklets'
|
||||
import {nanoid} from 'nanoid/non-secure'
|
||||
|
||||
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
|
||||
@@ -73,7 +69,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||
if (thumbRef) {
|
||||
// Measure the tapped image on the UI thread, then open with
|
||||
// the rect baked in so it's available from the first render.
|
||||
// Only the rect (plain data) goes through runOnJS — AnimatedRef
|
||||
// Only the rect (plain data) goes through scheduleOnRN — AnimatedRef
|
||||
// objects can't survive serialization across threads.
|
||||
const openWithRect = (rect: MeasuredDimensions | null) => {
|
||||
doOpen({
|
||||
@@ -83,11 +79,11 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||
),
|
||||
})
|
||||
}
|
||||
runOnUI(() => {
|
||||
scheduleOnUI(() => {
|
||||
'worklet'
|
||||
const rect = measure(thumbRef)
|
||||
runOnJS(openWithRect)(rect)
|
||||
})()
|
||||
scheduleOnRN(openWithRect, rect)
|
||||
})
|
||||
} else {
|
||||
doOpen(lightbox)
|
||||
}
|
||||
|
||||
@@ -8,12 +8,12 @@ import {
|
||||
} from 'react-native'
|
||||
import Animated, {
|
||||
measure,
|
||||
runOnJS,
|
||||
useAnimatedRef,
|
||||
useFrameCallback,
|
||||
} from 'react-native-reanimated'
|
||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||
import {WebView} from 'react-native-webview'
|
||||
import {scheduleOnRN} from 'react-native-worklets'
|
||||
import {Image} from 'expo-image'
|
||||
import {type AppBskyEmbedExternal} from '@atproto/api'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
@@ -164,7 +164,7 @@ export function ExternalPlayer({
|
||||
const isVisible = top <= realWinHeight - insets.bottom && bot >= insets.top
|
||||
|
||||
if (!isVisible) {
|
||||
runOnJS(setIsPlayerActive)(false)
|
||||
scheduleOnRN(setIsPlayerActive, false)
|
||||
}
|
||||
}, false) // False here disables autostarting the callback
|
||||
|
||||
|
||||
@@ -9,12 +9,12 @@ import {
|
||||
import {Pressable, useWindowDimensions, View} from 'react-native'
|
||||
import Animated, {
|
||||
Easing,
|
||||
runOnJS,
|
||||
useAnimatedStyle,
|
||||
useSharedValue,
|
||||
withTiming,
|
||||
} from 'react-native-reanimated'
|
||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||
import {scheduleOnRN} from 'react-native-worklets'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
@@ -69,7 +69,7 @@ export const ProgressGuideToast = forwardRef<
|
||||
duration: 400,
|
||||
easing: Easing.out(Easing.cubic),
|
||||
},
|
||||
() => runOnJS(setIsntOpen)(),
|
||||
() => scheduleOnRN(setIsntOpen),
|
||||
),
|
||||
)
|
||||
}, [setIsOpen, opacity])
|
||||
@@ -88,7 +88,7 @@ export const ProgressGuideToast = forwardRef<
|
||||
duration: 100,
|
||||
easing: Easing.out(Easing.cubic),
|
||||
},
|
||||
() => runOnJS(playCheckmark)(),
|
||||
() => scheduleOnRN(playCheckmark),
|
||||
),
|
||||
)
|
||||
translateY.set(0)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import {useCallback} from 'react'
|
||||
import {Pressable, View} from 'react-native'
|
||||
import Animated, {
|
||||
runOnJS,
|
||||
useAnimatedStyle,
|
||||
useSharedValue,
|
||||
withTiming,
|
||||
} from 'react-native-reanimated'
|
||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||
import {scheduleOnRN} from 'react-native-worklets'
|
||||
|
||||
import {
|
||||
ScaleAndFadeIn,
|
||||
@@ -41,7 +41,7 @@ export function NewMessagesPill({
|
||||
}, [scale])
|
||||
|
||||
const onPress = useCallback(() => {
|
||||
runOnJS(playHaptic)()
|
||||
scheduleOnRN(playHaptic)
|
||||
onPressInner?.()
|
||||
}, [onPressInner, playHaptic])
|
||||
|
||||
|
||||
@@ -4,13 +4,13 @@ import {Gesture, type GestureType} from 'react-native-gesture-handler'
|
||||
import Animated, {
|
||||
clamp,
|
||||
interpolate,
|
||||
runOnJS,
|
||||
useAnimatedStyle,
|
||||
useReducedMotion,
|
||||
useSharedValue,
|
||||
withSequence,
|
||||
withTiming,
|
||||
} from 'react-native-reanimated'
|
||||
import {scheduleOnRN} from 'react-native-worklets'
|
||||
|
||||
import {useHaptics} from '#/lib/haptics'
|
||||
import {atoms as a, tokens, useTheme} from '#/alf'
|
||||
@@ -111,7 +111,7 @@ export function SwipeToReply({
|
||||
if (pastThreshold && !hit.get()) {
|
||||
hit.set(true)
|
||||
runPop()
|
||||
runOnJS(playHaptic)('Medium')
|
||||
scheduleOnRN(playHaptic, 'Medium')
|
||||
} else if (!pastThreshold && hit.get()) {
|
||||
hit.set(false)
|
||||
}
|
||||
@@ -120,7 +120,7 @@ export function SwipeToReply({
|
||||
'worklet'
|
||||
// Only a clean end (finger lifted past threshold) triggers the reply.
|
||||
if (hit.get()) {
|
||||
runOnJS(onReply)()
|
||||
scheduleOnRN(onReply)
|
||||
}
|
||||
})
|
||||
.onFinalize(() => {
|
||||
|
||||
Reference in New Issue
Block a user