IwanQ
@IwanQ
Плохие времена часто дают прекрасные возможности

Почему так работает useState?

Доброго времени суток.

Есть компонент:

import { useEffect, useState } from 'react';

import { getRandomIntInRange } from './utills';

const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

const Test = () => {
  const [test] = useState(() => getRandomIntInRange(0, arr.length - 1));
  const [inputValue, setInputValue] = useState('');

  console.log('component', test); // после перерендера новое значение

  useEffect(() => {
    console.log('useEffect', test); // все ок, вызывается один раз, значение не меняется
  }, [test]);

  const handleInputChange = (e) => setInputValue(e.target.value);

  return <input type="text" onChange={handleInputChange} value={inputValue} />;
};


Где getRandomIntInRange обычная функция, которая получает случайное число в указанном диапозоне.

const getRandomIntInRange = (min = 0, max = 0) => {
  const minNumber = Math.ceil(min);
  const maxNumber = Math.floor(max);

  return Math.floor(Math.random() * (maxNumber - minNumber + 1) + minNumber);
};


Проблема в том, что я не понимаю, почему при перерендеривании компонента в обычном консоль логе ( console.log('component', test)) появляется новое значение, например:
component 5
...ввожу данные в инпут для перерендера компонента...
component 0
component 0


Т.е. значение как-будто бы изменилось, но при этом useEffect срабатывает только один раз, и значение в нем не меняется. Пример:
component 0
useEffect 3
...ввожу данные в инпут для перерендера компонента...
component 3
component 3


Объясните пожалуйста, почему так работает
  • Вопрос задан
  • 378 просмотров
Решения вопроса 1
@slide13
frontend/web-developer
Так работает из-за StrictMode в реакте, потому что в этом режиме на этапе разработки Реакт делает дополнительную проверку и делает вызовы некоторых методов дважды (собственно, это и видно в консоли):

Строгий режим не способен автоматически обнаруживать побочные эффекты, но помогает их отследить, сделав более детерминированными. Такое поведение достигается путём двойного вызова следующих методов:
  1. Методы constructor, render, и shouldComponentUpdate классового компонента
  2. Статический метод классового компонента getDerivedStateFromProps
  3. Тело функционального компонента
  4. Функции обновления (первый аргумент setState)
  5. Функции, переданные в useState, useMemo, или useReducer


В продакшен сборке будет все ок, можно проверить убрав обертку StrictMode, тогда в теле компонента и в useEffect значение test будет одинаковым и вызываться console.log("component", test); будет только один раз при вводе в инпут.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы