Context, порталы, error boundaries
Без prop drilling, рендер в другом месте DOM, ошибки изолированы по секциям.
Обновлено
Что такое Context, порталы и error boundaries
Три инструмента React для ситуаций, которые обычные props и состояние решают плохо:
| Инструмент | Какую проблему решает |
|---|---|
| Context | значение нужно многим компонентам глубоко в дереве, без props на каждом уровне |
| Портал | элемент нужно отрисовать в другом месте DOM (модалку, тултип), а не там, где он в дереве |
| Error boundary | ошибка в одном компоненте не должна ломать всю страницу |
Context
Проблема — prop drilling: user проходит через 5 компонентов, которые его не используют, только чтобы дойти до шестого.
const ThemeContext = createContext<'light' | 'dark'>('light') // значение по умолчанию
export function ThemeProvider({ children }: { children: React.ReactNode }) {
const [theme, setTheme] = useState<'light' | 'dark'>('light')
return <ThemeContext value={theme}>{children}</ThemeContext> // React 19: прямо <Context>
}
function Badge() {
const theme = use(ThemeContext) // или useContext(ThemeContext)
}| Правило | Подробности |
|---|---|
| побеждает ближайший провайдер сверху | можно переопределить значение для секции |
нет провайдера → значение по умолчанию из createContext |
|
| изменение значения перерисовывает всех потребителей | кладите в Context редко меняющиеся значения |
| новый объект на каждом рендере = лишние перерисовки | useMemo на значение или разделите на несколько контекстов |
| в Next провайдер — Client Component | кладёте в layout.tsx, оборачивая children (они остаются Server Components) |
Для глобального часто меняющегося состояния → Zustand / Redux.
Порталы
Модалка, отрисованная внутри карточки с overflow: hidden или в контексте наложения, обрезается или оказывается под другими элементами. createPortal рендерит её в другой узел DOM (обычно в конец body), но в дереве React она остаётся там, где вы её написали — получает Context, а события всплывают к React-родителям.
import { createPortal } from 'react-dom'
function Modal({ children }: { children: React.ReactNode }) {
return createPortal(<div className="fixed inset-0 grid place-items-center bg-black/40">{children}</div>, document.body)
}Современная альтернатива без портала: нативный элемент <dialog> с showModal() и Popover API (меню «Все темы» в этом приложении) — оба рендерятся в top layer, поверх всего, а фокусом и Esc управляет браузер.
Error boundaries
Ошибка, брошенная при рендере компонента, по умолчанию размонтирует всё приложение. Error boundary ловит ошибку и показывает запасной интерфейс только для этой секции.
| Где | Как |
|---|---|
| Next.js App Router | файл error.tsx в сегменте — см. Layout, состояния и навигация |
| обычный React | класс с getDerivedStateFromError или библиотека react-error-boundary |
Не ловят: ошибки в обработчиках событий (их ловят через try/catch), в асинхронном коде вне рендера, в Server Actions (их возвращают как состояние).
Коротко
- Context = передача без prop drilling; побеждает ближайший провайдер; только для редко меняющихся значений.
- Портал = рендер в другом месте DOM при сохранении места в дереве React;
<dialog>и popover — нативные альтернативы. - Error boundary = ошибка ломает только свою секцию; в Next —
error.tsx.