Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to clean up setInterval in useEffect using react hooks

I am trying to create a loading component that will add a period to a div periodically, every 1000ms using setInterval in React. I am trying to cleanup setInterval using the method described in the docs.

https://reactjs.org/docs/hooks-effect.html#example-using-hooks-1

import React, { useEffect, useState } from 'react'

const Loading = () => {
    const [loadingStatus, setLoadingStatus] = useState('.')
    const [loop, setLoop] = useState()
    useEffect(() => {
        setLoop(setInterval(() => {
            console.log("loading")
            setLoadingStatus(loadingStatus + ".")
        }, 1000))

        return function cleanup() {
            console.log('cleaning up')
            clearInterval(loop)
        }
    }, [])
    return (<p>
        {`Loading ${loadingStatus}`}
    </p>)
}
export default Loading

However , the loadingStatus variable only updates once and the setInterval loop doesnt get cleared even after the component stops mounting. Do I have to make this using a class component?

like image 254
Darruma Avatar asked Apr 19 '19 15:04

Darruma


People also ask

How do you clear setInterval in React useEffect?

Clearing setInterval in React To stop an interval, you can use the clearInterval() method. ... useEffect(() => { const interval = setInterval(() => { setSeconds(seconds => seconds + 1); }, 1000); return () => clearInterval(interval); }, []); ...

How do you clear the interval in React hook?

To clear a timeout or an interval in React with hooks:Use the clearTimeout() or clearInterval() methods to remove the timeout when the component unmounts.

How do I clean up using useEffect?

The hook comes with a cleanup function, which you might not always need, but it can come in handy. To invoke the cleanup function you can simply add a return function like so: useEffect(() => { // Your effect return () => { // Cleanup }; }, []); The cleanup can prevent memory leaks and remove unwanted things.

Can we use setInterval in useEffect?

A pretty straightforward functional component that holds a state in counter . The state is incremented every second thanks to the setInterval defined in the useEffect .


1 Answers

Dependencies are our hint for React of when the effect should run, even though we set an interval and providing no dependencies [], React wont know we want to run it more then once because nothing really changes in our empty dependencies [].

To get the desired result we need to think when we want to run the effect ?

We want to run it when loadingStatus changes, so we need to add loadingStatus as our dependency because we want to run the effect every time loadingStatus changes.

We have 2 options

Add loadingStatus as our dependency.

const Loading = () => {
  const [loadingStatus, setLoadingStatus] = useState(".");
  const [loop, setLoop] = useState();

  useEffect(
    () => {
      setLoop(
        setInterval(() => {
          console.log("loading");
          setLoadingStatus(loadingStatus + ".");
        }, 1000)
      );

      return function cleanup() {
        console.log("cleaning up");
        clearInterval(loop);
      };
    },
    [loadingStatus]
  );

  return <p>{`Loading ${loadingStatus}`}</p>;
};

Make our effect not aware that we use loadingStatus

const Loading = () => {
  const [loadingStatus, setLoadingStatus] = useState(".");

  useEffect(() => {
    const intervalId = setInterval(() => {
      setLoadingStatus(ls => ls + ".");
    }, 1000);

    return () => clearInterval(intervalId);
  }, []);

  return <p>{`Loading ${loadingStatus}`}</p>;
};

Read more here => a-complete-guide-to-useeffect

like image 92
Asaf Aviv Avatar answered Sep 29 '22 17:09

Asaf Aviv