Условные layouts

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


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

В TanStack Router layout представляет собой компонент, который оборачивает дочерние маршруты, предоставляя общую структуру интерфейса: навигацию, боковые панели, футеры, модальные окна. Условные layouts позволяют:

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

Ключевой элемент — использование функции children внутри route для динамического определения, какой layout должен применяться.


Пример условного layout

Рассмотрим пример, когда приложение имеет два основных типа страниц: публичные и защищённые.

import { createRouter, RouterProvider } from '@tanstack/router';
import PublicLayout from './layouts/PublicLayout';
import ProtectedLayout from './layouts/ProtectedLayout';
import HomePage from './pages/HomePage';
import DashboardPage from './pages/DashboardPage';
import LoginPage from './pages/LoginPage';
import { useAuth } from './auth';

const router = createRouter({
  routeTree: [
    {
      path: '/',
      element: ,
      children: [
        {
          path: '/',
          element: ({ params }) => {
            const { isAuthenticated } = useAuth();
            return isAuthenticated ?  : ;
          },
          children: [
            { path: '/', element:  },
            { path: '/dashboard', element:  },
            { path: '/login', element:  },
          ],
        },
      ],
    },
  ],
});

В этом примере компонент layout выбирается динамически на основе состояния isAuthenticated. Если пользователь авторизован, оборачивается ProtectedLayout, иначе — PublicLayout.


Использование loader для выбора layout

TanStack Router позволяет применять загрузчики данных (loader) для предварительной подготовки данных перед рендером маршрута. Это удобно для условных layouts, когда необходимо проверять роли пользователя или права доступа.

const dashboardRoute = {
  path: '/dashboard',
  loader: async ({ context }) => {
    const user = await context.getCurrentUser();
    if (!user) {
      throw redirect('/login');
    }
    return user;
  },
  element: ,
};

Здесь loader выполняет проверку и перенаправляет неавторизованных пользователей. Это позволяет разделять логику layout и сам контент страницы.


Вложенные условные layouts

TanStack Router поддерживает вложенные маршруты, что позволяет комбинировать несколько условных layouts. Например, внутри защищённого layout можно добавить layout для панели администратора:

const adminRoute = {
  path: '/admin',
  element: ({ user }) => user.role === 'admin' ?  : ,
  children: [
    { path: '/admin/users', element:  },
    { path: '/admin/settings', element:  },
  ],
};

Такой подход обеспечивает:

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

Варианты применения

  1. Аутентификация и авторизация — динамический выбор layout в зависимости от роли пользователя.
  2. Режимы отображения — например, мобильная и десктопная версии приложения.
  3. Темизация — разные темы могут накладываться через отдельные layouts.
  4. Контекстные панели — включение боковых панелей или модальных окон для определённых страниц.

Рекомендации по архитектуре

  • Использовать минимальное количество условных проверок внутри одного layout. Лучше делить layouts по логическим блокам.
  • Максимально применять loader и context для передачи состояния, чтобы layout оставался презентационным компонентом.
  • Для сложных приложений создавать отдельные поддеревья маршрутов с собственными layouts, чтобы избежать вложенных условных операторов в одном элементе.

Особенности производительности

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


Итоговая структура файла маршрутов

const routes = [
  {
    path: '/',
    element: ,
    children: [
      {
        path: '/',
        element: ({ user }) => user ?  : ,
        children: [
          { path: '/', element:  },
          { path: '/login', element:  },
          { path: '/dashboard', element:  },
        ],
      },
      {
        path: '/admin',
        element: ({ user }) => user?.role === 'admin' ?  : ,
        children: [
          { path: '/admin/users', element:  },
          { path: '/admin/settings', element:  },
        ],
      },
    ],
  },
];

Эта структура демонстрирует чистое разделение логики и контента, позволяя легко расширять приложение новыми conditional layouts без изменения существующих компонентов.