import { useState, useCallback } from 'react' import { SharedValue, useSharedValue, useDerivedValue, runOnJS, isSharedValue } from 'react-native-reanimated' /** * `runOnJS(_setValue)` is required because `useDerivedValue` runs on the UI thread — calling a React state setter directly from a worklet would crash. The derived value callback fires synchronously after the shared value changes, then bounces the update back to the JS thread via `runOnJS`. * * Closures inside the `useDerivedValue` callback must only reference serializable values; capturing non-serializable JS objects here will silently break on the UI thread. */ export function useAnimatedState(initialValue: SharedValue | T) { const sharedValue = isSharedValue(initialValue) ? initialValue : useSharedValue(initialValue) const [value, _setValue] = useState( isSharedValue(initialValue) ? initialValue.value : initialValue, ) useDerivedValue(() => { runOnJS(_setValue)(sharedValue.value) }) const setValue = useCallback((newValue: T) => { sharedValue.value = newValue if (isSharedValue(initialValue)) initialValue.value = newValue _setValue(newValue) }, []) return [value, setValue, sharedValue] as const } export function useAnimatedValue(initialValue: SharedValue | T): T { const [value] = useAnimatedState(initialValue) return value }