React: рендеринг, хуки и экосистема
React — это библиотека, которую все «знают» и которую мало кто понимает. Почти каждый разработчик может написать useState и вывести список через map, но когда интерфейс начинает «глючить» — список дёргается при вводе в поиск, эффект срабатывает дважды, форма перерендеривается на каждую клавишу, — начинается подгонка кода методом тыка. Разница между кодером и инженером на React ровно в одном: понимание того, что именно заставляет компонент перерендериваться и когда React решает это сделать.
В краткой версии учебника (v1) ты уже видел обзор хуков, управления состоянием и форм. В этом разделе мы идём глубже: под капот рендеринга, в ментальную модель эффектов, в trade-off’ы мемоизации, в границы применимости каждой библиотеки состояния. Это тот уровень, который отличает разработчика, прошедшего собеседование, от разработчика, которому не страшно дать ключевую фичу продукта.
Карта раздела
Заголовок раздела «Карта раздела»1. Как React рендерит: виртуальный DOM, reconciliation и батчинг
Заголовок раздела «1. Как React рендерит: виртуальный DOM, reconciliation и батчинг»Фундамент всего. Виртуальный DOM как представление UI в памяти, алгоритм reconciliation (сравнение деревьев), почему ключи — это не «просто айдишки», а вопрос корректности, и почему key={index} — прямая дорога к багам с потерей состояния. Отдельно разбираем батчинг обновлений: как React 18 сделал его автоматическим и в каких случаях это ломает привычные ожидания. Заканчиваем фазами render/commit и работой с Profiler — инструментом, который превращает догадки «кажется, тут тормозит» в измерения.
2. Состояние и эффекты: useState и useEffect без магии
Заголовок раздела «2. Состояние и эффекты: useState и useEffect без магии»Два хука, на которых стоит 90% React-кода. Разбираем ментальную модель useEffect как синхронизации с внешними системами (а не «lifecycle-метод после рендера»), зависимости и линт-правила, race conditions в запросах и AbortController как штатное решение. Отдельный блок — «когда эффект не нужен»: производные состояния, которые многие выносят в стейт и эффекты, хотя они должны считаться прямо в рендере.
3. Мемоизация, ссылки и редьюсеры: useMemo, useCallback, useRef, useReducer
Заголовок раздела «3. Мемоизация, ссылки и редьюсеры: useMemo, useCallback, useRef, useReducer»Самая недопонятая четвёрка хуков. Референциальная стабильность — главная причина использовать мемоизацию (а не «ускорение вычислений»), и мы на примерах покажем, когда useMemo/useCallback бесполезны и даже вредны. useRef как мутабельная ячейка, переживающая рендеры, включая callback-форму атрибута ref. useReducer — dispatch-модель, которая масштабирует локальное состояние лучше пачки связанных сеттеров.
4. Продвинутые хуки: useLayoutEffect, useId, useTransition, useDeferredValue, кастомные хуки
Заголовок раздела «4. Продвинутые хуки: useLayoutEffect, useId, useTransition, useDeferredValue, кастомные хуки»Инструменты редкие, но решающие конкретные проблемы: измерения DOM без визуального «прыжка», доступные связи label/input через useId, неблокирующие обновления для тяжёлых списков через useTransition. Плюс контракт кастомных хуков — главного механизма переиспользования логики в React: разберём useLocalStorage, useMediaQuery и useDebounce как эталонные примеры.
5. Управление состоянием: Zustand, Redux Toolkit, TanStack Query
Заголовок раздела «5. Управление состоянием: Zustand, Redux Toolkit, TanStack Query»Главная классификация, которую нужно принять до выбора библиотеки: локальное, серверное, URL- и глобальное состояние — четыре разных зверя. Zustand для клиентского глобального состояния без провайдеров, Redux Toolkit — когда оправдан его вес и инфраструктура, TanStack Query — серверное состояние (кэш, дедупликация, инвалидация), за который раньше отвечали ручные useEffect + fetch. Сравниваем по коду, а не по README.
Почему неконтролируемые формы рендерятся быстрее контролируемых, как register следит за DOM без ре-рендеров на каждую клавишу и что делать с компонентами-библиотеками через Controller. React Hook Form + Zod: схема как источник правды, вывод типов через z.infer, кросс-филдовая валидация через refine и async-проверки с сообщениями из сервера.
7. Роутинг: React Router v6+ и data routers
Заголовок раздела «7. Роутинг: React Router v6+ и data routers»Data routers (createBrowserRouter) изменили философию: данные грузятся до рендера через loader, мутации уходят через action, состояния навигации читаются из useNavigation, а ошибки ловятся в errorElement. Разбираем, как это стыкуется с TanStack Query, чтобы не было двух систем данных в одном приложении.
8. Тестирование: Vitest и Testing Library
Заголовок раздела «8. Тестирование: Vitest и Testing Library»Философия Testing Library — тестировать поведение, а не имплементацию: запросы по ролям, userEvent вместо fire-and-forget fireEvent, findBy* для асинхронщины, MSW для сетевого слоя. И честный список того, что тестировать не нужно, — чтобы тесты оставались активом, а не балластом.
Как проходить раздел
Заголовок раздела «Как проходить раздел»Порядок глав важен: механика рендеринга из первой главы — это ключ к пониманию всего остального. Хуки (главы 2–4) читай подряд и пиши примеры руками, наблюдая ререндеры через React DevTools. Главы 5–7 — прикладные: бери по мере надобности, но прочитай все, чтобы выбор инструмента был осознанным, а не «что первым в голову пришло». Глава 8 закрепляет всё тестами.
В конце раздела у тебя будет полный набор знаний для пет-проекта: формы с валидацией, роутинг с загрузкой данных, кэширование серверного состояния и юнит-тесты. Дальше — сборка приложения и первая оптимизация бандла в разделе о сборщиках.