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.
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
.