Как работает хук UseState?
Хуки
useState сохраняет значение между рендерами и планирует перерендер при его изменении. Под капотом React хранит состояние не в компоненте, а у себя — в связанном списке хуков на Fiber-узле.
Механика по шагам
const [count, setCount] = useState(0);- Первый рендер: React создаёт ячейку состояния, кладёт туда
0, возвращает значение и сеттер. - Повторные рендеры:
useState(0)возвращает не аргумент, а текущее сохранённое значение (аргумент игнорируется). - Вызов сеттера: React сравнивает новое значение со старым через
Object.is; если отличается — помечает компонент на перерендер и ставит обновление в очередь.
Почему хуки нельзя вызывать в условиях
Ячейки состояния сопоставляются с вызовами useState по порядку: первый вызов — первая ячейка, второй — вторая. Условный вызов сдвигает порядок, и состояния «перепутаются» — отсюда правило хуков.
Особенности сеттера
- Батчинг: несколько вызовов в одном обработчике (в React 18 — вообще везде) дают один перерендер.
- Замыкание:
countв текущем рендере — константа; послеsetCount(count + 1)переменная не изменится, новое значение придёт со следующим вызовом компонента. - Функциональная форма:
setCount((prev) => prev + 1)— очередь обновлений применяется последовательно, безопасно при множественных обновлениях. - Ленивая инициализация:
useState(() => expensive())— функция-инициализатор выполнится один раз.
setCount(count + 1);
setCount(count + 1); // итог: +1 (оба видят старый count)
setCount((c) => c + 1);
setCount((c) => c + 1); // итог: +2Коротко для собеседования
React хранит state в списке хуков Fiber-узла и сопоставляет его по порядку вызовов (поэтому хуки — только на верхнем уровне). Сеттер сравнивает значение по Object.is, батчит обновления и планирует перерендер; значение в текущем замыкании не меняется. Для зависимости от предыдущего значения — функциональная форма.