TanStack Router предоставляет мощный и гибкий механизм маршрутизации для современных приложений на JavaScript и TypeScript, позволяя организовать навигацию и управление состоянием. Одним из ключевых инструментов является контекст, с помощью которого можно передавать данные между маршрутами и компонентами без необходимости использовать глобальное состояние или пробрасывать пропсы через множество уровней.
Контекст в TanStack Router строится вокруг концепции
контекстных объектов, которые создаются на уровне
маршрута и доступны всем дочерним маршрутам. Каждый маршрут может
объявлять свои данные контекста с помощью свойства context,
которое принимает объект с нужными значениями. Эти данные могут быть
любыми: строки, объекты, функции или даже асинхронные значения.
Пример создания маршрута с контекстом:
import { createRouter, createRouteConfig } from '@tanstack/router'
const rootRoute = createRouteConfig()
.createRoute({
path: '/',
component: RootComponent,
context: {
theme: 'light',
user: { id: 1, name: 'Alice' }
},
})
В этом примере theme и user становятся
частью контекста для маршрута / и всех его потомков.
Для доступа к значениям контекста в компоненте используется хук
useContext. Он позволяет извлекать конкретные данные,
определенные на уровне маршрута, либо получать весь объект контекста
целиком.
Пример использования:
import { useContext } from '@tanstack/router'
function Header() {
const { theme, user } = useContext()
return (
<header className={theme === 'dark' ? 'dark-mode' : 'light-mode'}>
<h1>Привет, {user.name}</h1>
</header>
)
}
Ключевой момент: контекст маршрута автоматически наследуется дочерними маршрутами. Если дочерний маршрут не определяет собственный контекст, он будет использовать контекст родителя.
TanStack Router поддерживает динамический контекст, когда значения могут изменяться в зависимости от параметров маршрута или внешних данных. Для этого используется функция, возвращающая объект контекста, вместо статического объекта:
const profileRoute = createRouteConfig()
.createRoute({
path: '/profile/:userId',
component: Profile,
context: ({ params }) => ({
userId: params.userId,
fetchProfile: () => fetch(`/api/users/${params.userId}`).then(res => res.json())
}),
})
В этом случае контекст содержит userId и функцию
fetchProfile, которые вычисляются на основе текущего
параметра маршрута.
Дочерние маршруты могут переопределять контекст родителя, добавляя новые значения или изменяя существующие. Это позволяет локализовать данные, необходимые только для конкретной ветки маршрутов, без влияния на глобальный контекст приложения.
const dashboardRoute = createRouteConfig()
.createRoute({
path: '/dashboard',
component: Dashboard,
context: (parentContext) => ({
...parentContext,
dashboardData: { widgets: ['chart', 'table'] }
}),
})
Здесь dashboardData добавляется к существующему
контексту родителя, сохраняя при этом все его значения.
Контекст может содержать асинхронные значения, например данные, получаемые с сервера. Для этого используется механизм loader-функций, которые позволяют загружать данные до рендеринга компонента:
const postsRoute = createRouteConfig()
.createRoute({
path: '/posts',
component: Posts,
loader: async () => {
const response = await fetch('/api/posts')
const posts = await response.json()
return { posts }
},
context: ({ loaderData }) => ({
posts: loaderData.posts
}),
})
В этом примере данные posts становятся доступными в
контексте маршрута после завершения загрузки.
const appRouter = createRouter({
routeConfig: createRouteConfig()
.createRoute({
path: '/',
component: AppLayout,
context: { theme: 'dark' },
children: [
{
path: 'profile/:userId',
component: ProfilePage,
context: ({ params, parentContext }) => ({
...parentContext,
userId: params.userId,
fetchUser: () => fetch(`/api/users/${params.userId}`).then(res => res.json())
}),
},
{
path: 'settings',
component: SettingsPage,
context: { mode: 'advanced' },
},
],
}),
})
В этом примере:
theme наследуется всеми дочерними
маршрутами.profile/:userId комбинирует родительский
контекст с динамическими данными.settings переопределяет часть данных
локально, не влияя на профиль.Передача данных через контекст в TanStack Router позволяет организовать централизованное и при этом гибкое управление состоянием маршрутов, минимизируя необходимость в глобальных стореджах и упрощая архитектуру приложения. Контекст является мощным инструментом для построения сложных приложений с многоуровневой навигацией и динамическими данными.