0
votes

i want to add setInterval to be able to get new data from database without needing to refresh the page so i used useEffect,setInterval,useState to solve it,put intial state {refresh : false, refreshSells: null} and there is switch when it on refresh = true and refreshSells= setinterval() but i got annoying warning React Hook useEffect has a missing dependency: 'refreshSells'. Either include it or remove the dependency array and if i add refreshSells it will be unstoppable loop

const Sells = () => {
        const [allSells,setAllSells] = useState([])
        const [refresh,setRefresh] = useState(false)
        const [refreshSells , setRefreshSells] = useState(null)
        const [hidden,setHidden] = useState(true)
        useEffect(() => {
            Axios.get('/sells')
            .then(({data}) => {
                setAllSells(data.sells)
            })
            .catch(() => {
                alert('something went wrong,ask omar')
            })
        },[])
        useEffect(() => {
            if(refresh){
                setRefreshSells(setInterval(() => {
                    Axios.get('/sells')
                    .then(({data}) => {
                        setAllSells(data.sells)
                    })
                }, 60000));
            }
            else{
                clearInterval(refreshSells)
            }
            return () => clearInterval(refreshSells)
        },[refresh])
3
what is the purpose of setRefreshSells and setRefresh?? explain please - adel
Without useEffect the interval won't be cleared on unmount and you'll get "Can't perform a React state update on an unmounted component" - UjinT34

3 Answers

0
votes

setRefreshSells updates internal state and doesn't change refreshSells during current render. So return () => clearInterval(refreshSells) will try to clear the wrong interval.

You should use useRef hook for your interval:

const refreshSellsRef = useRef(null);
...
useEffect(() => {
    if(refresh){
        refreshSellsRef.current = setInterval(() => {
            Axios.get('/sells')
            .then(({data}) => {
                setAllSells(data.sells)
            })
        }, 60000);
        return () => clearInterval(refreshSellsRef.current);
    }
},[refresh])

Also note that return () => clearInterval(refreshSellsRef.current) will be called on unmount and when refresh changes. So you don't need else {clearInterval(...)}

0
votes

If your business logic allows to separate the 2 effects (automatic refresh every 60s + manual refresh after clicking some button), that would simplify the code for each independent effect:

    useEffect(() => {
        const interval = setInterval(() => {
            Axios.get('/sells')
            .then(({data}) => {
                setAllSells(data.sells)
            })
        }, 60000)
        return () => clearInterval(interval)
    }, [])

    useEffect(() => {
        if (refresh) {
            setRefresh(false)

            Axios.get('/sells')
            .then(({data}) => {
                setAllSells(data.sells)
            })
        };
    }, [refresh])

It looks like you forgot to setRefresh(false) after triggering the refresh, but I am not sure why you needed refreshSells in the first place...

0
votes

In the second useEffect you're updating the state refreshSells where useEffect expecting useCallback ref as a dependency. If you add refreshSells as a dependency to the useEffect then you may endup into memory leak issue.

So I suggest you try the below code which will solve your problem. by this you can also eliminate refreshSells

useEffect(() => {
    let interval;
    if (refresh) {
      interval = setInterval(() => {
         Axios.get('/sells')
          .then(({ data }) => {
            setAllSells(data.sells)
          });
      }, 4000);
    }
    return () => clearInterval(interval);
  }, [refresh]);