Search code examples
javascriptreactjsreact-nativelottie

React Native Lottie Animation Only Plays On First Tap


So essentially, I want to play the lottie animation everytime it is tapped. Here is my UI code for the lottie animation:

<Pressable onPress={playGame}>

<LottieView
   ref={loseAnimationRef}
   style={styles.egg}
   source={Lost}
   autoPlay={false}
   loop={false}
   onAnimationFinish={() => {
      resetAnimation();
   }}
/>

</Pressable>

Here is my state code for the lottie animation:

  const loseAnimationRef = useRef(null);

  const playGame = async () => {
    await mainGameLogicUC();
    playAnimation()
  };

  const playAnimation = () => {
      loseAnimationRef.current.play()
  }

  const resetAnimation = () => {
      loseAnimationRef.current.reset()
  }

On the first tap, the animation play perfefctly fine. But on all other taps, the animation won't play. I tried pausing the animation in the onAnimationFinish and then resuming it, but that also didn't work. Am I missing something?

EDIT

I got rid of the resetAnimation() in the onAnimationFinish and that solved the initial problem. But the thing is, I want the animation to be reset to the beginning every time. Why does it break when I reset the animation?


Solution

  • After coming back to this problem a few days later, I found the solution

    Playing the lottie animation seems to be considered a side effect, therefore, editing the references to the animations should be done in a useEffect hook

    The solution that worked for me:

    (again, in this code, I want the animation to reset to the beginning before the user taps the screen screen again.

    state code

      const isMounted = useRef(false);
    
      const [isWonAnimationShowing, setIsWonAnimationShowing] = useState(false);
      const [isAnimationPlaying, setIsAnimationPlaying] = useState(false);
      const loseAnimationRef = useRef(null);
      const winAnimationRef = useRef(null);
    
      useEffect(() => {
        if (isMounted.current) {
          if (isAnimationPlaying) {
            _playAnimation();
          } else {
            _resetAnimation();
          }
        } else {
          isMounted.current = true;
        }
      }, [isAnimationPlaying]);
    
    
      const playAnimation = () => {
        setIsAnimationPlaying(true);
      };
    
    
      const _playAnimation = () => {
        if (isWonAnimationShowing) {
          winAnimationRef.current.play();
        } else {
          loseAnimationRef.current.play();
        }
      };
    
    
      const resetAnimation = () => {
        setIsAnimationPlaying(false);
      };
    
    
      const _resetAnimation = () => {
        if (isWonAnimationShowing) {
          winAnimationRef.current.reset();
        } else {
          loseAnimationRef.current.reset();
        }
      };
    

    UI code

        <View style={styles.body}>
          <Pressable disabled={isAnimationPlaying} onPress={playGame}>
            {isWonAnimationShowing ? (
              <LottieView
                ref={winAnimationRef}
                style={styles.egg}
                source={Won}
                autoPlay={false}
                loop={false}
                onAnimationFinish={() => {
                  resetAnimation();
                }}
              />
            ) : (
              <LottieView
                ref={loseAnimationRef}
                style={styles.egg}
                source={Lost}
                autoPlay={false}
                loop={false}
                onAnimationFinish={() => {
                  resetAnimation();
                }}
              />
            )}
          </Pressable>
        </View>