Урок 08

useState: состояние компонента

Состояние — это данные, которые меняются со временем и влияют на отображение. Когда состояние меняется, React перерисовывает компонент.

Базовый useState

import { useState } from 'react';

function Counter() {
    const [count, setCount] = useState(0);

    return (
        <div>
            <p>Значение: {count}</p>
            <button onClick={() => setCount(count + 1)}>+1</button>
        </div>
    );
}

useState возвращает массив из двух элементов:

  • текущее значение
  • функция для его обновления

Начальное значение

const [count, setCount] = useState(0);       // число
const [name, setName] = useState('');        // строка
const [active, setActive] = useState(false); // булево
const [items, setItems] = useState<string[]>([]); // массив
const [user, setUser] = useState<User | null>(null); // объект или null

Обновление через функцию

Если новое значение зависит от предыдущего — используй функцию:

<button onClick={() => setCount((prev) => prev + 1)}>+1</button>

Это важно при нескольких обновлениях подряд: React применит все функции к актуальному значению.

Объекты в состоянии

Стейт нельзя мутировать — нужно создавать новый объект:

const [user, setUser] = useState({ name: 'Алиса', age: 25 });

// Неправильно
user.name = 'Боб';

// Правильно
setUser({ ...user, name: 'Боб' });

Массивы в состоянии

const [items, setItems] = useState<string[]>([]);

// Добавить
setItems([...items, 'новый']);

// Удалить
setItems(items.filter((item) => item !== 'ненужный'));

// Обновить элемент
setItems(items.map((item) =>
    item === 'старый' ? 'новый' : item
));

Несколько состояний

const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [age, setAge] = useState(0);

Если полей много и они логически связаны — можно объединить:

const [form, setForm] = useState({
    name: '',
    email: '',
    age: 0,
});

setForm({ ...form, name: 'Алиса' });

Ленивая инициализация

Если начальное значение вычисляется долго, передай функцию:

const [data, setData] = useState(() => {
    return JSON.parse(localStorage.getItem('data') ?? '[]');
});

Функция вызовется только один раз.

Состояние и рендер

Изменение состояния асинхронно. React батчит несколько обновлений в один рендер:

setCount(count + 1);
setCount(count + 1); // не сработает как ожидается

Правильно:

setCount((prev) => prev + 1);
setCount((prev) => prev + 1); // увеличит на 2

useState с типом

const [user, setUser] = useState<User | null>(null);
const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle');

Итоги

  • useState возвращает значение и функцию обновления
  • Обновление через функцию — когда зависит от предыдущего
  • Стейт не мутируется, а заменяется
  • Несколько вызовов setState батчатся
  • Начальное значение можно вычислять лениво