Как работает useState? Приведите пример.
Хук useState — это один из базовых хуков в React, предназначенный для добавления состояния в функциональные компоненты. До появления хуков в React (в версии 16.8) состояние можно было использовать только в классовых компонентах. С помощью useState функциональные компоненты получают возможность хранить и изменять данные между рендерами, не превращаясь в классы.
1. Что делает useState
Хук useState:
-
Инициализирует локальное состояние компонента.
-
Возвращает массив из двух элементов: текущего значения состояния и функции, с помощью которой можно изменить это значение.
-
При вызове функции обновления состояния React повторно рендерит компонент, чтобы отобразить новое состояние.
2. Синтаксис useState
const [state, setState] = useState(initialValue);
-
state — текущее значение состояния.
-
setState — функция, которая позволяет обновить значение.
-
initialValue — начальное значение состояния (может быть примитивом, объектом, массивом, функцией и т.д.).
3. Простой пример
import React, { useState } from 'react';
function Counter() {
const \[count, setCount\] = useState(0);
return (
<div>
<p>Счётчик: {count}</p>
<button onClick={() => setCount(count + 1)}>Увеличить</button>
<button onClick={() => setCount(count - 1)}>Уменьшить</button>
<button onClick={() => setCount(0)}>Сброс</button>
</div>
);
}
-
useState(0) создаёт переменную count, инициализированную значением 0.
-
setCount изменяет значение count, а React перерисовывает компонент с новым значением.
-
Каждое нажатие кнопки вызывает функцию, которая изменяет состояние.
4. Особенности работы useState
a. Состояние сохраняется между рендерами
Даже если компонент перерисовывается (вызван новый рендер), состояние, заданное через useState, не теряется:
function Example() {
const \[value, setValue\] = useState('hello');
// при каждом рендере value сохраняется и используется
}
b. Обновление состояния вызывает повторный рендер
Когда вызывается setState, React повторно вызывает компонент, чтобы отобразить новое состояние. Обновление не происходит мгновенно — это асинхронный процесс, React может оптимизировать несколько обновлений.
setCount(count + 1); // инициирует ререндер с новым значением
c. Можно использовать несколько состояний
В одном компоненте можно вызвать useState несколько раз — каждое состояние будет независимым:
const \[name, setName\] = useState('');
const \[age, setAge\] = useState(0);
const \[isVisible, setIsVisible\] = useState(true);
5. Передача функции вместо значения
Если начальное значение должно вычисляться, можно передать функцию, которая будет вызвана один раз при инициализации (ленивая инициализация):
const \[count, setCount\] = useState(() => {
console.log('Вычисляем начальное значение');
return 10;
});
Это полезно при тяжёлых вычислениях — чтобы они выполнялись один раз, а не при каждом рендере.
6. Обновление состояния на основе предыдущего
Из-за асинхронности обновлений лучше использовать функциональную форму setState, когда новое значение зависит от старого:
setCount(prevCount => prevCount + 1);
Такой способ надёжнее, особенно если обновлений несколько подряд или они происходят внутри setTimeout, setInterval и т.п.
7. Работа с объектами и массивами в useState
a. Объекты
Если состояние — объект, при обновлении нужно явно сохранять неизменные свойства:
const \[user, setUser\] = useState({ name: 'Анна', age: 25 });
setUser(prevUser => ({
...prevUser,
age: 26
}));
Если просто вызвать setUser({ age: 26 }), то поле name потеряется — новый объект полностью заменит старый.
b. Массивы
const \[todos, setTodos\] = useState(\[\]);
setTodos(prevTodos => \[...prevTodos, { id: 1, text: 'Новая задача' }\]);
Любое изменение — добавление, удаление, обновление — должно производиться через копирование массива и возврат нового.
8. Поведение при повторной установке того же значения
Если вызвать setState с тем же значением, которое уже установлено, React не будет ререндерить компонент:
const \[count, setCount\] = useState(5);
setCount(5); // ничего не произойдёт
Это сделано для оптимизации.
9. useState и ререндер
Важно понимать: состояние привязано к порядку вызова хуков. Если в компоненте меняется количество или порядок вызовов useState, возникнет ошибка.
function Example() {
if (someCondition) {
const \[x, setX\] = useState(0); // ❌ так делать нельзя
}
}
Хуки должны вызываться на верхнем уровне компонента, без условий и циклов.
10. Пример с инпутом (управляемый компонент)
function NameForm() {
const \[name, setName\] = useState('');
const handleChange = (e) => {
setName(e.target.value);
};
return (
<div>
<input type="text" value={name} onChange={handleChange} />
<p>Ваше имя: {name}</p>
</div>
);
}
Значение name хранится в состоянии и обновляется при каждом вводе. Таким образом, React полностью управляет значением инпута — это контролируемый компонент.
11. Совместимость с другими хуками
useState часто используется вместе с другими хуками:
-
useEffect — реагирует на изменение состояния.
-
useRef — работает с DOM без потери состояния.
-
useReducer — альтернатива для сложных состояний.
12. Когда не использовать useState
-
Когда данные не должны сохраняться между рендерами — лучше использовать обычные переменные.
-
Когда нужно взаимодействовать с внешними хранилищами (например, Redux или Zustand).
-
Когда нужно глобальное состояние, доступное из разных компонентов.
Хук useState — основа для управления данными внутри компонента. Он делает функциональные компоненты «живыми», позволяя им изменять своё поведение и внешний вид в зависимости от пользовательских действий или логики.