Search code examples
reactjsuse-effect

React useEffect: how to clearInterval?


I made a count down button.

How could I clearInterval when the button will be unmounted? (like componentWillUnmount)

const CooldownButton = ({
  cooldown,
  ...props
}) => {
  const defaultClasses = useStyles();

  const [count, setCount] = useState(cooldown);
  const [timer, setTimer] = useState(null);

  useEffect(() => {
    if (count > 0 && !timer) {
      setTimer(
        setInterval(() => {
          if (count > 0) {
            setCount((prevState) => prevState - 1);
          }
          if (count === 0) {
            clearInterval(timer);
            setTimer(null);
          }
        }, 1000)
      );
    }
  }, [count, timer]);

  useUpdateEffect(() => {
    setCount(cooldown);
  }, [cooldown]);

  return (
    // ...
        <Typography
          size={24}
          className={clsx(defaultClasses.counter, classes?.counter)}
          {...counterProps}
        >
          {`${new Date(count * 1000)
            .toISOString()
            .substr(...(count >= 3600 ? [11, 8] : [14, 5]))}`}
        </Typography>
    // ...
  );
};

This will cause an infinite render:

  useEffect(() => {
    if (count > 0 && !timer) {
      // ...
    }
    return () => {
      clearInterval(timer);
      setTimer(null);
      
    }
  }, [count, timer]);

Solution

  • if just wanner auto countdown, do not need setInterval,
    when count changed, useEffect will run

      const [count, setCount] = useState(cooldown);
    
    
      useEffect(() => {
        if (count > 0) {
           const timer = setTimeout(()=> {
              setCount(count - 1);
           }, 1000);
           return ()=> clearTimeout(timer);
        }
      }, [count, timer]);