javascriptreactjsreact-nativesetintervalclearinterval

setInterval Doesn't work with useState hook


In this code there is two buttons that should enable and disable a ProgressBar. I used setInterval method for enabling ProgressBar and clearInterval for disabling ProgressBar in two separated functions. First button works but second one (disabling button) doesn't work Do you have any idea how can i fix it?


 let [ProgresValue, setProgresValue] = useState(0);

    var ID = null;

    const StartProgress = () => {
        ID = setInterval(() => {
            if (ProgresValue <= 1) {
                setProgresValue(ProgresValue = ProgresValue + 0.01)}
        }, 100);}




    const StopProgress = () => {

         clearInterval(ID); }

this is return section:


return (
        <Fragment>
            <Text>Progress Bar:{parseFloat((ProgresValue * 100).toFixed(3))}%</Text>

            {
                (Platform.OS === 'android')
                    ?
                    (<ProgressBarAndroid
                        styleAttr='Horizontal'
                        indeterminate={false}
                        progress={ProgresValue}
                        style={{ width: 300 }}

                    />)
                    :
                    (<ProgressViewIOS
                        progress={ProgresValue}

                    />) }

 <TouchableHighlight onPress={StartProgress} style={styles.button}><Text style={{ color: 'white', textAlign: 'center' }}>Start Prgress</Text></TouchableHighlight>
 <TouchableHighlight onPress={StopProgress} style={styles.button} ><Text style={{ color: 'white', textAlign: 'center' }} >Stop Progress</Text></TouchableHighlight>

  </Fragment>

 )

Solution

  • You are not updating your state after stoping the timer, so component is not being updated. You might want to use useEffect hook with cleanup. Try something like that:

    const [shouldCount, setShouldCount] = useState(false);
    const [progressValue, setProgressValue] = useState(0);
    useEffect(() => {
       if(shouldCount){
          const interval = setInterval(() => setProgressValue(prevVal => prevVal + 1),
            1000
          );
          return () => clearInterval(interval);
       }
    }, [shouldCount, progressValue]);
    

    and then just pass setShouldCount count with true/false to onPress event.

    EDIT: also I forgot to put pass the array of values as second argument to useEffect, this is done to prevent running a side effect if the values have not changed.