javascriptreactjsreact-nativesetintervalclearinterval

clearInterval doesn't work (React-Native Javascript)


I am currently working on a React-Native app, for some reason I am unable to clear the interval that I have set earlier. It simply wont work no matter what I try. here's my code if you guys could give it a look I would greatly appreciate it. It's all inside a Gesture Handler.

  const rotation = useSharedValue(0);
  const pullDistance = useSharedValue(0);
  const rotationValue = useSharedValue(0);
  const stretchTo = useSharedValue(0);
  var animationLoop;

  const animation = (rot) => {
    const EASING = Easing.elastic(1.5);
    animationLoop = setInterval(() => {
      rotationValue.value = withSequence(
        withTiming(-10 + rot, {
          duration: 100,
          easing: EASING,
        }),
        withTiming(10 + rot, {
          duration: 100,
          easing: EASING,
        })
      );
    }, 200);
  };

  const clearAnimation = (animationLoop) => {
    clearInterval(animationLoop);
    rotationValue.value = 0;
    console.log("cleared");
  };

  const pullingToMatchGestureHandler = useAnimatedGestureHandler({
    onStart: () => {
      console.log("start");
      console.log("animating");
      const rotationValue = rotation.value;
      pullDistance.value = 1;
      runOnJS(animation)(rotationValue);
    },

    onActive: (event) => {
      const direction = 0;
      const distance = Math.sqrt(
        Math.pow(event.translationX, 2) + Math.pow(event.translationY, 2)
      );
      if (event.translationX > 0 && -event.translationY > 0) {
        direction = Math.atan(-event.translationY / event.translationX);
      } else if (event.translationX < 0 && -event.translationY > 0) {
        direction =
          Math.PI + Math.atan(-event.translationY / event.translationX);
      } else if (event.translationX < 0 && -event.translationY < 0) {
        direction =
          Math.PI + Math.atan(-event.translationY / event.translationX);
      } else if (event.translationX > 0 && -event.translationY < 0) {
        direction =
          2 * Math.PI + Math.atan(-event.translationY / event.translationX);
      }

      let rotationInRad = (rotation.value * Math.PI) / 180;
      rotationInRad = -rotationInRad + Math.PI / 2;
      while (rotationInRad < 0) {
        rotationInRad = rotationInRad + 2 * Math.PI;
      }
      const differenceAngle = rotationInRad - direction;
      if (
        -distance * Math.cos(differenceAngle) > 0 &&
        -distance * Math.cos(differenceAngle) < window.width / 5
      )
        pullDistance.value = -distance * Math.cos(differenceAngle) * 2.5;
    },

    onFinish: (event) => {
      console.log("end animation");
      runOnJS(clearAnimation)(animationLoop);
      cancelAnimation(rotationValue);
      pullDistance.value = 0;
    },
  });

The log('cleared') runs so there shouldn't be a problem in the execution of the clearAnimation function. I dont know what to do.


Solution

  • The problem seems to be with JS runtime context, I don't use React Native, but from what I can gather it uses worker threads (worklet) to keep the GUI nice and responsive.

    So -> var animationLoop; is potentially not running in the same JS context as code that's been run in runOnJS This then means the interval created inside these runOnJS will not see this var.

    The solution appears to be use useSharedValue to store the interval Id, this can then be shared between each runOnJS.