Home > OS >  How to stop setInterval define outside the useEffect
How to stop setInterval define outside the useEffect

Time:12-02

I want to make a progress bar which increase it's value in every 5 seconds. I used setInterval which increase the state value and trying to clearInterval once state value is 100. But it's not clearing the interval and state value is not getting changed properly

import {useState, useEffect} from 'react';
function App() {
  const [percentage,setPercentage] = useState(99)
  let progressInterval = setInterval(()=>{
    console.log(percentage);
    setPercentage(percentage 1);
  },10000);
  // useEffect(()=> {
  // },[])
  useEffect(() => {
    
    if(percentage === 100) {
      console.log("completed");
      clearInterval(progressInterval);
    }
  }, [percentage])
  const progress = {
    backgroundColor: 'yellow',
    width: `${percentage}%`,
    textAlign: 'right',
  }
  const fullWidth = {
    border: '1px solid black',
    backgroundColor: '#eff',
    margin: '10px'
  }
  return (
    <>
      <div style={fullWidth}>
        <div style={progress}>{percentage}%</div>
      </div>
    </>
  );
}

export default App;

CodePudding user response:

When you change the state your component will be rerender and your progressInterval variable will be reinitialize.

you should initizalize the variable of interval inside a callback function:

import {useState, useEffect, useCallback} from 'react';

let progressInterval = '';
function App() {
  const [percentage,setPercentage] = useState(99);
  const initInterval = useCallback(() => {
    progressInterval = setInterval(()=>{
      console.log(percentage);
      setPercentage(percentage 1);
    },10000);
  }, []);

  useEffect(() => {
    if(percentage === 100) {
      console.log("completed");
      clearInterval(progressInterval);
    }
  }, [percentage])
  const progress = {
    backgroundColor: 'yellow',
    width: `${percentage}%`,
    textAlign: 'right',
  }
  const fullWidth = {
    border: '1px solid black',
    backgroundColor: '#eff',
    margin: '10px'
  }
  return (
    <>
      <div style={fullWidth}>
        <div style={progress}>{percentage}%</div>
      </div>
    </>
  );
}

export default App;

CodePudding user response:

If progressInterval can be a state variable, this might be the solution:

function App() {
  const [percentage, setPercentage] = useState(99);
  const [progressInterval, setProgressInterval] = useState();

  useEffect(() => {
    let progressInterval = setInterval(() => {
      console.log(percentage);
      setPercentage((prev) => prev   1);
    }, 10000);

    setProgressInterval(progressInterval);

    // Optional but a recommendation
    // Clearing the interval if component unmounts before reaching 100 percent
    return () => clearInterval(progressInterval);

  }, []);

  useEffect(() => {
    if (percentage === 100) {
      console.log("completed");
      clearInterval(progressInterval);
    }
  }, [percentage]);

... rest of the code

}

CodePudding user response:

You can set a return function to your useEffect like this

  useEffect(() => {
                const timer = setTimeout(() => {
    
                  if(progress < 0.9){
                    setProgress(progress   0.2);
                  }
                  else{
                    retrieveData();
                  }
    
                }, 1000);
                return () => {
                  clearTimeout(timer);
                };
              }, [progress]);
  • Related