Outlet и рендеринг дочерних маршрутов

TanStack Router предоставляет мощный и гибкий механизм работы с вложенными маршрутами через компонент Outlet. Этот механизм позволяет строить сложные и иерархические структуры страниц, где родительский маршрут может содержать один или несколько дочерних, а их рендеринг происходит динамически в контексте родительского компонента.


1. Принцип работы Outlet

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

  • Если текущий маршрут не имеет дочерних, Outlet ничего не рендерит.
  • Если текущий маршрут имеет несколько вложенных маршрутов, Outlet рендерит тот дочерний маршрут, путь к которому совпадает с URL.

Пример базовой структуры маршрутов с Outlet:

import { RouterProvider, createRouter, Route } from '@tanstack/router';

const Home = () => 
Главная страница
; const Dashboard = () =>

Панель управления

; const Analytics = () =>
Аналитика
; const Settings = () =>
Настройки
; const router = createRouter({ routes: [ { path: '/', component: Home, }, { path: '/dashboard', component: Dashboard, children: [ { path: 'analytics', component: Analytics }, { path: 'settings', component: Settings }, ], }, ], }); function App() { return ; }

В данном примере при переходе на /dashboard/analytics будет рендериться компонент Dashboard, а внутри него через Outlet — компонент Analytics.


2. Поддержка глубокой вложенности

TanStack Router позволяет строить маршруты с произвольной глубиной вложенности. Каждый уровень маршрута может содержать свой Outlet, обеспечивая рендеринг дочерних маршрутов только в контексте соответствующего родителя.

const Reports = () => 

Отчеты

; const MonthlyReport = () =>
Ежемесячный отчет
; const router = createRouter({ routes: [ { path: '/dashboard', component: Dashboard, children: [ { path: 'reports', component: Reports, children: [ { path: 'monthly', component: MonthlyReport }, ], }, ], }, ], });

При переходе на /dashboard/reports/monthly рендерится иерархия: DashboardReportsMonthlyReport.


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

TanStack Router поддерживает передачу данных из родительских маршрутов в дочерние с помощью loader-функций и context. Данные, загруженные на уровне родителя, могут быть использованы в любом дочернем компоненте через хуки useLoaderData или useRouteContext.

const Dashboard = () => {
  const data = useLoaderData(); // данные, загруженные для /dashboard
  return (
    

Панель управления

Привет, {data.userName}

); };

Loader для родительского маршрута:

const router = createRouter({
  routes: [
    {
      path: '/dashboard',
      component: Dashboard,
      loader: async () => ({ userName: 'Алексей' }),
      children: [
        { path: 'analytics', component: Analytics },
        { path: 'settings', component: Settings },
      ],
    },
  ],
});

В этом случае дочерние маршруты (Analytics, Settings) могут получать доступ к данным родителя через useRouteContext('dashboard').


4. Программное управление рендерингом дочерних маршрутов

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

const Dashboard = () => {
  const isAdmin = true; // пример условия
  return (
    

Панель управления

{isAdmin && }
); };

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


5. Обработка ошибок и fallback

Outlet поддерживает отображение fallback-компонентов при загрузке данных или при ошибках. Использование компонента или fallback-компонента внутри родителя позволяет локализовать ошибки:

const Dashboard = () => (
  

Панель управления

Ошибка загрузки дочернего маршрута
}>
);

Таким образом, ошибка загрузки дочернего маршрута не нарушает работу всего родителя и позволяет пользователю видеть понятное сообщение об ошибке.


6. Преимущества подхода

  • Четкая иерархия компонентов: каждый родитель управляет рендерингом своих дочерних маршрутов.
  • Повторное использование родительских компонентов: родительские layout-компоненты могут использоваться для нескольких дочерних маршрутов.
  • Гибкая загрузка данных: loader-функции и контексты упрощают передачу данных вниз по иерархии.
  • Поддержка динамических условий: рендеринг дочерних маршрутов можно контролировать через состояние или пользовательские права.