'useEffect won't update state

I'm creating a simple tomato app and got stuck on the timer update logic.

I'm using a useEffect to update a timer, but for some reason after the one second, the timer stop decreasing. It seems it's not getting updated since the console log keep printing the initial values .

here's a testable stackbliz

here's the full component:

import './Tomato.css';
import { useState, useEffect } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faPlay, faPause, faArrowsRotate, faArrowDown, faArrowUp } from '@fortawesome/free-solid-svg-icons'

function Tomato() {
    
    const [settings, setSettings] = useState({session: 25, break: 5});
    const [timer, setTimer] = useState({minutes: '25', seconds: '00', active: false, isBreak: false});
    

    useEffect(() => {
        let timerInterval;

        if(timer.active) {
            timerInterval = setInterval(() => {
                let seconds = parseInt(timer.seconds);
                let minutes = parseInt(timer.minutes);
                console.log(seconds, ':',minutes)
                if(seconds === 0 && minutes === 0) {
                //  setTimer( {
                //      minutes: settings.isBreak ? settings.session : settings.break, 
                //      seconds: '00', 
                //      active: true, 
                //      isBreak: !settings.isBreak
                //  })
                //  // TODO BIP
                } else if(seconds === 0) {
                    const newTimer = {
                        ...timer,
                        minutes: timer.minutes-1,
                        seconds: '59',
                    }
                    setTimer( newTimer)
                } else {
                    console.log('in')
                    seconds = seconds - 1;
                    // this is not working as expected
                    setTimer( {
                        ...timer,
                        seconds: seconds < 10 ? '0'+seconds : seconds+''
                    })
                }
            }, 1000);
        } else {
            clearInterval(timerInterval);
        }

        return function cleanup() {
            clearInterval(timerInterval);
        };
    }, [timer.active]);


    const toggleTimer = (value) => {
        setTimer({ ...timer, active: value})
    }

    const refreshTimer = () => {
        setTimer({ 
            minutes: settings.session,
            seconds: '00', 
            active: false,
            isBreak: false
        })
    }

    const editSettings =  (type, val) => {
        if(timer.active) return
        const newSettings = { ...settings }
        newSettings[type] +=val;
        if(newSettings[type] > 60) {
            newSettings[type] = 60
        }
        if(newSettings[type] < 1) {
            newSettings[type] = 1
        }
        setSettings(newSettings)
    }

    return (
        <div className="Tomato">
            
            <h2 className="title">Session</h2>
            <div className="session-container">
                <div className='session-value'>{timer.minutes}:{timer.seconds}</div>
                <div className='controls-container'>
                    <span className='icon-container'>
                        <FontAwesomeIcon onClick={()=>{ toggleTimer(true)}} icon={faPlay} />
                    </span>
                    <span className='icon-container'>
                        <FontAwesomeIcon onClick={()=>{ toggleTimer(false)}} icon={faPause} />
                    </span>
                    <span className='icon-container'>
                        <FontAwesomeIcon onClick={()=>{ refreshTimer()}} icon={faArrowsRotate} />
                    </span>
                </div>
            </div>

            <h2 className="title">Session Length</h2>
            <div className="setting-container">
                <span className='icon-container' onClick={()=> editSettings('session', -1)}>
                    <FontAwesomeIcon icon={faArrowDown} />
                </span>
                <div className="setting-value">{settings.session}</div>
                <span className='icon-container' onClick={()=> editSettings('session', 1)}>
                    <FontAwesomeIcon icon={faArrowUp} />
                </span>
            </div>
            
            <h2 className="title">Break Length</h2>
            <div className="setting-container">
                <span className='icon-container' onClick={()=> editSettings('break', -1)}>
                    <FontAwesomeIcon icon={faArrowDown} />
                </span>
                <div className="setting-value">{settings.break}</div>
                <span className='icon-container' onClick={()=> editSettings('break', +1)}>
                    <FontAwesomeIcon icon={faArrowUp} />
                </span>
            </div>
            
        </div>
        );
    }
    
    export default Tomato;
    


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source