Антон Ларичев

Введение
Хуки появились в React 16.8 и полностью изменили подход к написанию компонентов. Они позволяют использовать состояние и другие возможности React внутри функциональных компонентов, без классов. В этой статье разберём три самых важных хука: useState, useEffect и useContext. На практических примерах вы поймёте, когда и как их применять, а также какие ошибки чаще всего совершают новички.
Хуки решают сразу несколько проблем: устраняют дублирование логики между компонентами, упрощают тестирование и делают код более читаемым. Но у них есть строгие правила: вызывать только на верхнем уровне функции и только из React-компонентов или других хуков.
useState — управление состоянием
useState — самый базовый хук. Он добавляет локальное состояние в функциональный компонент. Хук возвращает массив из двух элементов: текущее значение и функцию для его обновления.
import { useState } from 'react';
function Counter() {
// объявляем переменную состояния count с начальным значением 0
const [count, setCount] = useState(0);
return (
<div>
<p>Вы кликнули {count} раз</p>
<button onClick={() => setCount(count + 1)}>
Увеличить
</button>
</div>
);
}
При обновлении состояния React автоматически перерисовывает компонент. Если новое значение зависит от предыдущего, используйте функциональную форму — это безопаснее при асинхронных обновлениях.
// правильно: используем предыдущее значение через колбэк
setCount(prev => prev + 1);
// рискованно: при нескольких вызовах подряд может потеряться обновление
setCount(count + 1);
Для сложных объектов помните: React не делает глубокого слияния. Нужно вручную копировать предыдущее состояние через спред-оператор.
const [user, setUser] = useState({ name: 'Аня', age: 25 });
// обновляем только одно поле, остальные сохраняем
setUser(prev => ({ ...prev, age: 26 }));
useEffect — побочные эффекты
useEffect запускает код после рендера компонента. Он подходит для запросов к API, подписок на события, работы с таймерами и любых операций, которые не должны блокировать отрисовку интерфейса.
import { useState, useEffect } from 'react';
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
// выполняется после рендера и при изменении userId
fetch(`/api/users/${userId}`)
.then(res => res.json())
.then(data => setUser(data));
}, [userId]); // массив зависимостей
if (!user) return <p>Загрузка...</p>;
return <h1>{user.name}</h1>;
}
Второй аргумент — массив зависимостей. Он определяет, когда эффект перезапустится:
[]— эффект сработает только один раз после монтирования[userId]— эффект перезапустится при измененииuserId- без массива — эффект будет выполняться после каждого рендера
Если эффект что-то подписывает или запускает таймер, верните функцию очистки. Она вызовется перед следующим запуском эффекта и при размонтировании компонента.
useEffect(() => {
const timer = setInterval(() => {
console.log('тик');
}, 1000);
// функция очистки предотвращает утечки памяти
return () => clearInterval(timer);
}, []);
useContext — общий доступ к данным
useContext решает проблему «props drilling» — передачи пропсов через множество уровней компонентов. Сначала создаём контекст, оборачиваем дерево в провайдер, а затем читаем значение в любом дочернем компоненте.
import { createContext, useContext, useState } from 'react';
// создаём контекст с дефолтным значением
const ThemeContext = createContext('light');
function App() {
const [theme, setTheme] = useState('dark');
return (
<ThemeContext.Provider value={theme}>
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar() {
// не нужно передавать theme через пропсы
return <ThemedButton />;
}
function ThemedButton() {
// получаем значение из ближайшего провайдера
const theme = useContext(ThemeContext);
return <button className={theme}>Кнопка</button>;
}
Контекст хорошо подходит для темы оформления, текущего пользователя, языка интерфейса. Но не используйте его для часто меняющихся данных — каждое изменение value перерисовывает всех потребителей.
Частые ошибки
Условный вызов хуков. Хуки нельзя вызывать внутри условий, циклов или вложенных функций. React определяет порядок хуков по позиции вызова.
// неправильно: хук внутри условия
if (isLoggedIn) {
const [name, setName] = useState('');
}
// правильно: условие внутри хука
const [name, setName] = useState('');
if (isLoggedIn) {
// используем name здесь
}
Пропуск зависимостей в useEffect. Если внутри эффекта используется переменная из компонента, она должна быть в массиве зависимостей. Иначе вы получите устаревшее значение.
Бесконечный цикл рендеров. Если в эффекте обновлять состояние, которое находится в его зависимостях, без условия — компонент будет ререндериться бесконечно.
// бесконечный цикл
useEffect(() => {
setCount(count + 1);
}, [count]);
Мутация состояния. Не изменяйте объекты и массивы напрямую — React не заметит изменения. Всегда создавайте новый объект через спред или методы вроде map, filter.
Заключение
Хуки — это фундамент современной разработки на React. useState управляет локальным состоянием, useEffect обрабатывает побочные эффекты, а useContext упрощает передачу данных через дерево компонентов. Освоив эти три хука, вы покроете 80% повседневных задач во фронтенде.
Дальше изучите useReducer для сложной логики состояния, useMemo и useCallback для оптимизации производительности, а также научитесь писать собственные хуки. Главное правило — соблюдайте порядок вызова и не забывайте про массив зависимостей.






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