javascriptreactjsreact-nativeasynchronousreact-native-gesture-handler

(React Native Gesture Handler) Tried to synchronously call function from a different thread


I am trying to change state from a pan gesture (React Native Gesture Handler).

const [localShowRecents, setLocalShowRecents] = useState(false)
const translateY = useSharedValue(0);

const gesture = Gesture.Pan()
      .onStart(() => {
        context.value = { y: translateY.value }
      })
      .onUpdate((event) => {
        //console.log(event.translationY);
        translateY.value = event.translationY + context.value.y;
        translateY.value = Math.max(translateY.value, MAX_TRANSLATE_Y)
      })
      .onEnd(() => {
      if (translateY.value > -SCREEN_HEIGHT / 32){
        setLocalShowRecents(true); //change state
      }
}

When I try to update state from the ".onEnd()" function, I get the error "Tried to synchronously call function from a different thread." How do I properly change state from the gesture handler?


Solution

  • Your Reanimated components work on the device's UI thread. The rest of your code will work on the device's JS thread. The way your code is written, it tries to call a Javascript function on the UI thread, which causes the error you're seeing.

    This is why Reanimated includes the runOnJS method. Instead of

      setLocalShowRecents(true)
    

    you can use

      runOnJS(setLocalShowRecents)(true);
    

    Note the modified call signature - runOnJS(fn)(args). You can read more about runOnJS here in the Reanimated docs.