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

168
Visualizações
Why does setInterval works in useEffect but not when inside functional component context (see inside if condition)?

I was building UI for a dictionary that shows a word followed by its meaning. The word switches through a setInterval. In the below code I'm setting up the setInterval initially and then on some events. Here I'm just focused on the initial setInterval.

Although I'm quite experienced in React I am still not able to grab my head around why the setInterval works when inside useEffect hook but not from the if condition.

To replicate just comment out the if condition and uncomment useEffect block.

Can someone please explain?

import React, { useState, useEffect } from 'react';
import Dictionary from './Dictionary.json';
import './App.css';

const words = Object.keys(Dictionary);
let currentInterval;

function App() {
  const [randomWord, setRandomWord] = useState(words && words[Math.round(Math.random() * words.length)]);
  const [wordGenerationDuration, setWordGenerationDuration] = useState(10000);

  function selectRandomWord() {
    setRandomWord(words[Math.round(Math.random() * (words.length - 1))]);
  }
  
  if(!currentInterval) {
    currentInterval = setInterval(selectRandomWord, wordGenerationDuration);
  }

  // useEffect(
  //   () => {
  //     currentInterval = setInterval(selectRandomWord, wordGenerationDuration);
  //   }, []
  // )


  return (
    <div className='App'>
      <div className='dictionary-wrapper'>
        <p className='dictionary-word'>
          {randomWord}
        </p>
        <p className='dictionary-meaning'>
          {Dictionary[randomWord]}
        </p>
        <p className='next-button cursor-pointer'>
          <span
            onClick={
              () => {
                clearInterval(currentInterval);
                selectRandomWord();
                currentInterval = setInterval(selectRandomWord, wordGenerationDuration);
              }
            }
          >
            Next Word
          </span>
        </p>
        <p>
          <span>Auto Switch Duration:</span>
          <input
            className='dictionary-input'
            type='number'
            placeholder={wordGenerationDuration / 1000}
            onChange={
              (evt) => {
                const wordGenerationDuration = Math.max(evt.target?.value * 1000, 10000);
                clearInterval(currentInterval);
                setWordGenerationDuration(wordGenerationDuration);
                currentInterval = setInterval(selectRandomWord, wordGenerationDuration);
              }
            }
            min='10'
          />
        </p>
      </div>
    </div>
  );
}

export default App;

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

0

Your original interval callback is a function defined within your component (selectRandomWord).

When your component re-renders, the currentInterval will be set so your interval will not be redefined. The existing interval will then refer to the previous render's version of selectRandomWord which is no longer updating the state of the current render.

What you should really do is

  1. Store the interval hook in a ref
  2. Register your interval within useEffect(), and
  3. Make sure you clear the interval in the component cleanup
function App() {
  const interval = useRef()
  const [randomWord, setRandomWord] = useState(words && words[Math.round(Math.random() * words.length)]);
  const [wordGenerationDuration, setWordGenerationDuration] = useState(10000);

  function selectRandomWord() {
    setRandomWord(words[Math.round(Math.random() * (words.length - 1))]);
  }

  useEffect(() => {
    if (!interval.current) {
      interval.current = setInterval(selectRandomWord, wordGenerationDuration)
    }

    // cleanup
    return () => {
      clearInterval(interval.current)
    }
  }, [])

You can also clear the interval at any time using

clearInterval(interval.current)

See also https://reactjs.org/docs/hooks-faq.html#is-there-something-like-instance-variables

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