Контекст для конкретных маршрутов

В TanStack Router управление состоянием и данными маршрутов основано на принципе изоляции контекста. Каждый маршрут может иметь собственный контекст, что позволяет хранить специфичные для него данные, методы и параметры, не смешивая их с глобальным состоянием приложения. Контекст маршрута создаётся через объект context в конфигурации маршрута и доступен во всех дочерних компонентах, связанных с этим маршрутом.

Создание контекста маршрута

Контекст создаётся при определении маршрута с помощью функции createRoute или через объект routes. Например, можно определить маршрут с локальным состоянием:

import { createRoute } from '@tanstack/router';
import { createContext } from 'react';

const UserContext = createContext(null);

const userRoute = createRoute({
  path: '/user/:id',
  component: UserPage,
  context: UserContext,
});

Здесь UserContext будет доступен внутри компонента UserPage и всех вложенных компонентов, без необходимости использовать глобальные состояния или пропсы.

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

Для работы с контекстом маршрута используется стандартный React-хук useContext. При этом доступ к контексту строго привязан к маршруту, который его определил:

import { useContext } from 'react';

function UserProfile() {
  const user = useContext(UserContext);

  return <div>{user.name}</div>;
}

Такой подход гарантирует, что данные пользователя будут уникальны для каждого экземпляра маршрута /user/:id.

Передача данных через контекст

Контекст маршрута может содержать как статические данные, так и динамические функции для управления состоянием. Например:

const userRoute = createRoute({
  path: '/user/:id',
  component: UserPage,
  context: createContext({
    user: null,
    setUser: () => {},
  }),
});

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

function UserPage() {
  const { user, setUser } = useContext(UserContext);

  useEffect(() => {
    fetchUserData().then(data => setUser(data));
  }, []);

  return <div>{user ? user.name : 'Загрузка...'}</div>;
}

Наследование контекста в дочерних маршрутах

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

const dashboardRoute = createRoute({
  path: '/dashboard',
  component: Dashboard,
  context: createContext({ theme: 'light' }),
});

const analyticsRoute = createRoute({
  path: '/dashboard/analytics',
  component: Analytics,
  parent: dashboardRoute,
});

В Analytics можно получить доступ к theme родительского контекста через useContext(dashboardRoute.context).

Динамическая инициализация контекста

Иногда необходимо инициализировать контекст на основе параметров маршрута. Для этого используется функция createContext с ленивой загрузкой:

const userRoute = createRoute({
  path: '/user/:id',
  component: UserPage,
  context: createContext((params) => ({
    userId: params.id,
    user: null,
  })),
});

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

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

  • Контекст маршрута следует использовать для данных и функций, которые относятся только к конкретному маршруту, чтобы избежать загрязнения глобального состояния.
  • Для сложных приложений с вложенными маршрутами можно комбинировать родительский и дочерний контексты для централизованного управления данными.
  • Для асинхронных данных рекомендуется инициализировать контекст через useEffect или функции загрузки, чтобы избежать блокировки рендеринга.

Взаимодействие контекста с loader и action

TanStack Router позволяет связывать контекст маршрута с функциями loader и action. Контекст передаётся в эти функции автоматически:

const userRoute = createRoute({
  path: '/user/:id',
  component: UserPage,
  context: createContext({ user: null }),
  loader: async ({ params, context }) => {
    const data = await fetchUser(params.id);
    context.setUser(data);
  },
});

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

Применение в масштабируемых приложениях

Использование контекста для конкретных маршрутов позволяет строить модульную структуру, где каждый маршрут и его дочерние компоненты автономны. Это особенно важно для крупных приложений, где разделение ответственности снижает сложность поддержки и тестирования. Контекст маршрута становится инструментом для локальной инкапсуляции состояния, минимизируя вероятность конфликтов между независимыми частями интерфейса.