Введение в React Hooks
Что такое Hooks?
Заголовок раздела «Что такое Hooks?»Hooks появились в React 16.8 и позволяют использовать состояние и другие возможности React в функциональных компонентах, без необходимости писать классы.
До Hooks логика состояния была привязана к классовым компонентам, что делало переиспользование логики сложным (HOC, render props). Hooks решают эту проблему — логику можно вынести в кастомный хук и использовать в любом компоненте.
Правила хуков
Заголовок раздела «Правила хуков»Правило 1: Вызывай только на верхнем уровне
Заголовок раздела «Правило 1: Вызывай только на верхнем уровне»// ❌ Нельзя — Hook внутри условияfunction Component({ show }: { show: boolean }) { if (show) { const [count, setCount] = useState(0); // ОШИБКА }}
// ✅ Можно — Hook на верхнем уровнеfunction Component({ show }: { show: boolean }) { const [count, setCount] = useState(0); if (!show) return null; return <div>{count}</div>;}Правило 2: Вызывай только из React-функций
Заголовок раздела «Правило 2: Вызывай только из React-функций»// ❌ Нельзя — Hook в обычной функцииfunction fetchData() { const [data, setData] = useState(null); // ОШИБКА}
// ✅ Можно — только в компонентах и кастомных хукахfunction MyComponent() { const [data, setData] = useState(null); return <div>{data}</div>;}
// ✅ Можно — в кастомных хуках (начинаются с "use")function useFetch(url: string) { const [data, setData] = useState(null); // ... return data;}React 18: Новшества
Заголовок раздела «React 18: Новшества»Автоматический batching
Заголовок раздела «Автоматический batching»До React 18 setState в обработчиках событий батчился, но не в асинхронных операциях:
// React 17: 2 рендераsetTimeout(() => { setCount(c => c + 1); // рендер 1 setFlag(f => !f); // рендер 2}, 1000);
// React 18: 1 рендер (автоматический batching)setTimeout(() => { setCount(c => c + 1); // } setFlag(f => !f); // } один рендер}, 1000);Если нужно отключить batching:
import { flushSync } from 'react-dom';
flushSync(() => setCount(c => c + 1)); // немедленный рендерflushSync(() => setFlag(f => !f)); // ещё один рендерTransitions (useTransition)
Заголовок раздела «Transitions (useTransition)»Позволяет помечать обновления как “не срочные”:
import { useState, useTransition } from 'react';
function SearchResults() { const [query, setQuery] = useState(''); const [results, setResults] = useState<string[]>([]); const [isPending, startTransition] = useTransition();
function handleChange(value: string) { setQuery(value); // срочное: обновить поле ввода
startTransition(() => { // не срочное: можно прерывать setResults(expensiveSearch(value)); }); }
return ( <> <input value={query} onChange={e => handleChange(e.target.value)} /> {isPending ? <span>Загрузка...</span> : <List items={results} />} </> );}useDeferredValue
Заголовок раздела «useDeferredValue»Альтернатива useTransition когда нельзя контролировать источник обновления:
import { useDeferredValue } from 'react';
function SearchResults({ query }: { query: string }) { const deferredQuery = useDeferredValue(query); // deferredQuery отстаёт от query — React перерисует с новым значением, // когда будет свободен const results = expensiveSearch(deferredQuery); return <List items={results} />;}Встроенные хуки (обзор)
Заголовок раздела «Встроенные хуки (обзор)»| Хук | Назначение |
|---|---|
useState | Локальное состояние |
useEffect | Побочные эффекты |
useContext | Чтение контекста |
useReducer | Сложное состояние |
useCallback | Мемоизация функций |
useMemo | Мемоизация значений |
useRef | Ссылки / мутабельные значения |
useId | Уникальные ID (React 18) |
useTransition | Не срочные обновления (React 18) |
useDeferredValue | Откладывание обновления (React 18) |
useSyncExternalStore | Внешние хранилища (React 18) |
Порядок выполнения
Заголовок раздела «Порядок выполнения»function Example() { console.log('1. render');
useEffect(() => { console.log('3. after paint (effect)'); return () => console.log('cleanup'); });
useLayoutEffect(() => { console.log('2. after DOM mutation (layout effect)'); });
return <div />;}// Порядок: 1 → 2 → paint → 3