useOutletContext

useOutletContext — это хук из библиотеки React Router, предназначенный для передачи данных от родительского маршрута к дочерним маршрутам без необходимости пробрасывать их через пропсы. Он является важным инструментом для организации вложенных маршрутов и упрощает работу с общим состоянием между компонентами маршрутов.

Основные принципы работы

  • Хук вызывается только внутри компонента, который рендерится через <Outlet />. Это гарантирует, что контекст будет доступен только дочерним маршрутам, а не случайным компонентам.
  • Данные передаются от родителя через атрибут context компонента <Outlet>.
  • Полученные значения можно использовать как обычное состояние или объект с методами, что делает useOutletContext удобным для передачи функций и данных.

Пример передачи контекста:

import { Outlet } from 'react-router-dom';

function Parent() {
  const sharedData = {
    user: { name: 'Alex', role: 'admin' },
    logout: () => console.log('User logged out')
  };

  return (
    <div>
      <h1>Панель пользователя</h1>
      <Outlet context={sharedData} />
    </div>
  );
}

Получение данных в дочернем маршруте

Для доступа к переданному контексту используется хук useOutletContext:

import { useOutletContext } from 'react-router-dom';

function Child() {
  const { user, logout } = useOutletContext();

  return (
    <div>
      <p>Привет, {user.name}!</p>
      <button onCl ick={logout}>Выйти</button>
    </div>
  );
}

В этом примере дочерний компонент получает объект sharedData, определённый в родителе, и может напрямую использовать его свойства и методы.

Типизация с TypeScript

Для безопасной работы с данными можно использовать дженерики:

interface SharedData {
  user: { name: string; role: string };
  logout: () => void;
}

const context = useOutletContext<SharedData>();

Это позволяет TypeScript проверять правильность типов и предотвращает ошибки при обращении к полям объекта.

Использование с вложенными маршрутами

useOutletContext особенно полезен в случаях, когда маршруты вложены глубоко, и необходимо передавать данные через несколько уровней:

<Routes>
  <Route path="dashboard" element={<Parent />}>
    <Route path="settings" element={<Child />} />
    <Route path="profile" element={<AnotherChild />} />
  </Route>
</Routes>

Все дочерние маршруты (settings, profile) могут использовать один и тот же контекст, переданный через <Outlet context={...} />. Это позволяет избежать повторной передачи данных через пропсы на каждом уровне.

Отличия от пропсов и контекста React

  • В отличие от обычных пропсов, useOutletContext не требует явного пробрасывания данных на каждом уровне компонента.
  • В отличие от React Context, данные доступны только внутри маршрутов, использующих <Outlet>, что делает их локальными для маршрутов и предотвращает утечки состояния в глобальное дерево компонентов.

Практические сценарии применения

  1. Панель администратора: общий объект пользователя и функции управления сессией.
  2. Форма с шагами: состояние текущего шага передаётся между дочерними маршрутами без внешнего хранилища.
  3. Модульная структура: компоненты, подключаемые к разным маршрутам, используют общие данные, например, настройки приложения или тему.

Советы по использованию

  • Передавать только необходимые данные, чтобы не создавать «тяжёлый» контекст.
  • Использовать типизацию для предотвращения ошибок при доступе к полям объекта.
  • Не использовать вне компонентов <Outlet>, чтобы избежать undefined при вызове хука.

useOutletContext обеспечивает удобный, безопасный и структурированный способ обмена данными между родительским и дочерними маршрутами, позволяя создавать сложные, вложенные маршруты без потери управляемости состояния.