Cancelling react native's react spring async animation on component unmount

1k views Asked by At

I have a component that loops an animation using react-spring library. When the component is dismounted via "isVisible", react complains that there is memory leak:

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.

Below is a snippet of the codes causing the issue.

Is there any better way / right way to loop react-spring's animation without memory leak issues?

import React from 'react';
import { useTransition } from 'react-spring';

export let component = (props) => {

  const { isVisible } = props;

   const transitions = useTransition(isVisible, null, {
        config: { duration: 5000 },
        from: { opacity: 1, translateX: 500 },
        enter: item => async (next, cancel) => {
            while (isVisible) {
                await next({ config: { duration: 5000 }, translateX: -1 * 500 });
                await next({ config: { duration: 50 }, opacity: 0 });
                await next({ config: { duration: 50 }, translateX: 500 });
                await next({ config: { duration: 50 }, opacity: 1 });
            };
        },
    });
    
    return transitions.map(({ item, key, props}) => (
      <AnimatedView
        key={key}
        style={[
          {
            transform: [{ translateX: props.translateX }],
            opacity: props.opacity
          }
        ]}
      >
       {/.../}
      </AnimatedView>
    ))
}
2

There are 2 answers

1
Peter Ambruzs On

Do you tried the cleanup with useEffect? As you control the transition with isVisible, I would add a switch to it called mounted. You can switch it off in the useEffect cleanup function. So the animation will stop.

const [mounted, setMounted] = React.useState(true);
const isVisible = props.isVisible && mounted;

useEffect(() => {
  return () => {
    setMounted(false);
  };
}, []);
0
Isaac Khoo On

Found a solution to this issue by dismounting the component from the parent directly.

let component = () => { ... };

let parent = () => {
    
    const [isVisible, setIsVisible] = useState(true);

    return isVisible && <Component />;
}

When the component gets dismounted via isVisible, the while animation loop no longer throws an error