Как использовать setInterval в реагировать? - PullRequest
2 голосов
/ 07 января 2020

Я пытаюсь сделать простую функцию setInterval для игры на машинке, но она продолжает зависать в зависимости от моего синтаксиса или вообще не обновляется, как сейчас.

Как мне заставить это обновляться каждую секунду и вызывать функции в операторе if?

const [counter, setCounter] = useState(10);

useEffect(() => {
  let timer = setInterval(() => {
    setCounter(counter - 1);

    if (counter === 0) {
      setWordIndex(wordIndex + 1);
      setLives(lives - 1);
      life.play();
      setCounter(10);
    }
  }, 1000);
}, []);

********* Edit ******* ********

Это то, что у меня сейчас работает. В первом ответе исправлена ​​асинхронная c проблема с счетчиком, не уменьшавшимся, но мне пришлось переместить оператор if за пределы useEffect, чтобы исправить то, что, по моему мнению, было вызвано этой же проблемой.

 useEffect(() => {
    let timer = setInterval(() => {
      setCounter( counter => counter - 1);
    }, 1000);
  }, []);
  if (counter == 0) {
    setWordIndex(wordIndex + 1);
    setLives(lives - 1);
    life.play();
    setCounter(10);
  }

Ответы [ 3 ]

1 голос
/ 07 января 2020

Использовать функцию обратного вызова в функции setCounter. Поскольку вы вызываете обновление состояния в асинхронной c функции. Рекомендуется обновлять состояние на основе предыдущего состояния.

const [counter, setCounter] = useState(10);
useEffect(() => {
    let timer = setInterval(() => {
        setCounter(counter => {
            const updatedCounter = counter - 1;
            if (updatedCounter === 0) {
                setWordIndex(wordIndex + 1);
                setLives(lives - 1);
                life.play();
                return 10;
            }
            return updatedCounter;
        }); // use callback function to set the state

    }, 1000);
    return () => clearInterval(timer); // cleanup the timer
}, []);
0 голосов
/ 07 января 2020

Предыдущие ответы не учитывают значения счетчика, которые не обновляются немедленно. Они также подвержены утечкам памяти, поскольку setInterval не очищается.

const [counter, setCounter] = useState(10);
useEffect(() => {
  let timer = setInterval(() => {
    setCounter( counter => {
        const nC = counter - 1;
        if (nC === 0) {
           setWordIndex(wordIndex + 1);
           setLives(lives - 1);
           life.play();
           return 10;
        }
        return nC;
     });
  }, 1000);
  return () => clearInterval(timer);
}, []);
0 голосов
/ 07 января 2020

Предыдущие ответы не учитывали другие состояния - wordIndex и жизни и не включали чистые интервалы

Желательно использовать обратный вызов setState внутри setIntervals и очищать интервал при следующем вызове useEffect

  const [counter, setCounter] = React.useState(10);
  React.useEffect(() => {
    let timer = setInterval(() => {
      // It's advisable to use callback setState inside setIntervals
      setCounter(prev => {
        if (prev !== 0) return prev - 1;

        setWordIndex(wordIndex + 1);
        setLives(lives - 1);
        life.play();    
        return 10;
      });
    }, 1000);

    // And clear the interval next useEffect call
    return () => clearInterval(timer);
  }, [wordIndex, lives]);
...