Концепция layout-компонентов

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

Определение layout-компонента

Layout-компонент — это React-компонент, который используется для оборачивания одного или нескольких дочерних маршрутов. Его основная задача — задавать общую структуру интерфейса, например шапку (header), боковую панель (sidebar), футер (footer) или другие элементы, которые должны быть видимы на нескольких маршрутах.

Ключевые особенности layout-компонентов:

  • Наличие области для вложенных маршрутов. Внутри layout-компонента обязательно должен использоваться <Outlet /> из TanStack Router, куда будут рендериться дочерние маршруты.
  • Изоляция состояния и логики. Layout-компонент может содержать собственное состояние и эффекты, которые будут общими для всех дочерних маршрутов.
  • Повторное использование. Один layout может быть использован для нескольких маршрутов, что позволяет уменьшить дублирование кода и поддерживать консистентный интерфейс.

Создание layout-компонента

Пример базового layout-компонента:

import React from "react";
import { Outlet } from "@tanstack/router";

function MainLayout() {
  return (
    <div>
      <header>
        <h1>Приложение</h1>
      </header>
      <aside>
        <nav>
          <ul>
            <li><a href="/dashboard">Dashboard</a></li>
            <li><a href="/settings">Settings</a></li>
          </ul>
        </nav>
      </aside>
      <main>
        <Outlet />
      </main>
      <footer>
        © 2026 Все права защищены
      </footer>
    </div>
  );
}

export default MainLayout;

В этом примере <Outlet /> определяет место, куда будут подставляться компоненты дочерних маршрутов.

Интеграция layout-компонента с маршрутизатором

Для подключения layout-компонента к маршрутам используется объект route. Layout-маршрут определяется аналогично обычному маршруту, но его дочерние маршруты будут рендериться внутри <Outlet />.

Пример маршрутизации с layout:

import { createRouter, createRouteConfig } from "@tanstack/router";
import MainLayout from "./layouts/MainLayout";
import DashboardPage from "./pages/DashboardPage";
import SettingsPage from "./pages/SettingsPage";

const routeConfig = createRouteConfig()
  .createRoute({
    path: "/",
    component: MainLayout,
    children: [
      { path: "dashboard", component: DashboardPage },
      { path: "settings", component: SettingsPage },
    ],
  });

const router = createRouter({ routeConfig });

export default router;

В этом примере MainLayout служит контейнером для всех маршрутов /dashboard и /settings.

Особенности работы с вложенными layout-компонентами

TanStack Router поддерживает многоуровневую вложенность layout-компонентов. Это позволяет создавать иерархию интерфейса, где каждый уровень отвечает за свой набор элементов и областей рендера.

Пример вложенной структуры:

const routeConfig = createRouteConfig()
  .createRoute({
    path: "/",
    component: MainLayout,
    children: [
      {
        path: "dashboard",
        component: DashboardLayout, // вложенный layout
        children: [
          { path: "analytics", component: AnalyticsPage },
          { path: "reports", component: ReportsPage },
        ],
      },
      { path: "settings", component: SettingsPage },
    ],
  });

Здесь DashboardLayout является дочерним layout-компонентом для маршрутов analytics и reports. Такой подход позволяет изолировать разные части интерфейса и управлять отдельными зонами страницы независимо друг от друга.

Использование состояния и эффектов в layout-компонентах

Layout-компоненты могут хранить состояние, которое будет доступно всем дочерним маршрутам. Например, это удобно для управления глобальным боковым меню, авторизацией пользователя или текущими настройками темы интерфейса.

function MainLayout() {
  const [isSidebarOpen, setSidebarOpen] = React.useState(true);

  return (
    <div className={`layout ${isSidebarOpen ? "sidebar-open" : ""}`}>
      <aside>
        <button onCl ick={() => setSidebarOpen(!isSidebarOpen)}>Toggle Sidebar</button>
      </aside>
      <main>
        <Outlet />
      </main>
    </div>
  );
}

Такое состояние будет сохраняться при навигации между дочерними маршрутами, поскольку layout-компонент остается в дереве компонентов до тех пор, пока пользователь находится внутри маршрутов, связанных с этим layout.

Важные рекомендации

  • Минимизировать логику в layout-компоненте, если она не относится ко всем дочерним маршрутам, чтобы избежать ненужного рендера.
  • Использовать несколько layout-компонентов для разных областей приложения (например, административная панель и публичная часть сайта).
  • Правильно организовывать вложенность, чтобы не создавать слишком глубокие иерархии, которые усложняют поддержку и отладку маршрутов.

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