В 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 и actionTanStack 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);
},
});
Таким образом, контекст обеспечивает сквозное хранение состояния от загрузки данных до отображения компонента, что упрощает архитектуру и улучшает читаемость кода.
Использование контекста для конкретных маршрутов позволяет строить модульную структуру, где каждый маршрут и его дочерние компоненты автономны. Это особенно важно для крупных приложений, где разделение ответственности снижает сложность поддержки и тестирования. Контекст маршрута становится инструментом для локальной инкапсуляции состояния, минимизируя вероятность конфликтов между независимыми частями интерфейса.