Переключение значения внутри компонента React с useState не работает

#reactjs

#reactjs

Вопрос:

У меня есть компонент React. Внутри этого компонента я хочу, чтобы что-то росло и уменьшалось каждую секунду. Я пытаюсь использовать useState для этого.

Этот код не работает. Он просто повторно устанавливает значение false. Я не совсем понимаю, почему. Есть мысли?

   const [fullWidth, setFullWidth] = useState(false);

  let interval;
  useEffect(() => {
    startToggle();
    return () => {
      clearInterval(interval)
    }
  }, []);

  const startToggle = () => {
    interval = setInterval(() => {
      setFullWidth(!fullWidth);
    }, 1000)
  }
  

Комментарии:

1. Вы уверены, что он устанавливает его в false , нет true ?

Ответ №1:

Даже если startToggle объявлено снаружи useEffect , оно все равно должно передаваться fullWidth как зависимость внутри массива эффектов.

 const { useEffect, useState } = React;

const App = () => {
  const [fullWidth, setFullWidth] = useState(false);

  useEffect(() => {
    const interval = setInterval(() => {
      setFullWidth((f) => !f);
    }, 1000);
    
    return () => {
      clearInterval(interval);
    };
  }, []);

  return fullWidth.toString();
}

ReactDOM.render(<App />, document.getElementById("root"));  
 <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

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

Комментарии:

1. В этом случае было бы лучше перейти fullWidth к startToggle явно, чтобы сделать это… более явно. В качестве альтернативы, setFullWidth(fullWidth => !fullWidth); также может быть использовано.

2. @FelixKling Это круто, так как тогда нам не нужно менять массив зависимостей. Однако, как насчет принципа подключения — reactjs.org/docs/… Это правило здесь не нарушено, Феликс?

3. @FelixKling ваше решение сработало. Почему это имеет значение?

4. @kinduser: я думаю, это так. Но также нет необходимости создавать новый интервал при каждом рендеринге, если мы уже можем получить «текущее» значение другим способом, IMO. Но каждый может выбрать, что ему подходит 🙂

5. @JSeabolt: в вашем решении интервал запускается только один раз при первом рендеринге и startToggle (с первого рендеринга) всегда будет ссылаться на fullWidth из этого первого вызова рендеринга, когда он имел значение false . Передавая функцию обратного вызова, вы указываете setFullWidth , чтобы она давала вам текущее значение этого состояния. Это обычная ловушка, в которую можно попасть.