Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

249
Visualizações
How to get setInterval in React to change a state variable?

I want the following code to start counting down from a number after a user logs in.

The following code shows simple shows 0 in the console.log every second, but doesn't seem to set the state variable secondsLeft to 8, nor does it count this variable down.

const [secondsLeft, setSecondsLeft] = useState(0);

...

const handleButton = async () => {
    const response = await fetch('http://localhost:5001/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ username, password })
    });
    setUsername('');
    setPassword('');
    if (response.ok) {
        const data = await response.json();
        setCurrentUser(prev => ({ ...prev, ...data.user }));
        setMessage(`User: ${currentUser.firstName}`);
        setSecondsLeft(8);
        setInterval(() => {
            setSecondsLeft(prev => secondsLeft -1);
            console.log(secondsLeft);
        }, 1000);
    } else {
        setMessage('bad login');
    }
}

How can I get setInterval to decrease the value of secondsLeft each second?

about 4 years ago · Juan Pablo Isaza
3 Respostas
Responde à pergunta

0

This is a very common pitfall in React. You, understandably, seem to assume that setSecondsLeft takes effect immediately, but it doesn't. Hence, secondsLeft will not be 8 to start with. There is another problem that secondsLeft is not updated in your interval. This should work instead:

    setSecondsLeft(8);
    setInterval(() => {
        setSecondsLeft(prev => {
          console.log(prev);
          return prev - 1;
        });
    }, 1000);
about 4 years ago · Juan Pablo Isaza Relatório

0

Actually it works, but you see in the console 8 every time setIntervall callback runs, because it only access to initial value of secondsLeft and it doesn't recognize the update of secondsLeft in later updates. You can run the below example and see it updates state everyTime setInterval callback runs but in the console you always see 0.

function App() {
  const [secondsLeft, setSeconds] = React.useState(0);
  let timerId = null;
  const handleClick = () => {
    setSeconds(8);
    timerId = setInterval(()=> {
      console.log(secondsLeft)
      setSeconds(prev => prev - 1);
    }, 1000)
  };

  React.useEffect(()=> {
    return ()=> clearInterval(timerId)
  }, [])

  return (
    <div>
      <h2>{secondsLeft}</h2>
      <button onClick={handleClick}>Start interval</button>
    </div>
  );
}

ReactDOM.render(React.createElement(App, {}), document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.0/umd/react-dom.production.min.js"></script>

<div id="root"></div>

about 4 years ago · Juan Pablo Isaza Relatório

0

I tried to do the things in the traditional way,

useEffect(() => {
  setInterval(() => {
     console.log("update", st);
     setSt((prev) => prev + 1);
  }, 500);
}, []);

But this doesn't work because during the running of useState on the first render, the setInterval keeps a copy of prev for itself which it tries to update again and again, for eg: setSt(prev => prev+1) but since prev is always = 1 due to the closure that it has for itself, the value don't really update.


Then I tried to use useCallback hook which rerenders the function on dependency change and thus provided prev as dependency but sadly that also hand't worked most probably due to same reason as above but by different means.

You can see the way I tried in the commented out code of codesandbox.


At last, I tried my hands by creating a setIntervalHack which can work similar to setInterval, but is not really a setInterval.

Here are the steps I followed.

  • You can think of setInterval as a recursive function that runs again and again after an interval, but the drawback is that we can't pass an argument to it due to which update becomes stale.
  • So, I passed an argument to the setIntervalHack which depicts the new state to be updated with.
  • To wait for some time, I used promises to await for the recursion again to run and in the argument of recalling recursive function setIntervalHack, I passed (currentState+1)

and this is the way I tried to achieve the similar functionality of setInterval

Here is the link to the code https://codesandbox.io/s/happy-swartz-ikqdn?file=/src/focus.js

Note: You can go on /focus route in codesandbox's browser and open the console

PS: I did an increment to the counter, not the decrement. You can do the similar by decrementing on each recursion

about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda