Доки по разработке
This project is maintained by teniryte
<Link />import { Link } from '@tanstack/react-router'
<Link
to="/blog/$postId"
params={{ postId: 42 }}
search={{ highlight: true }}
preload="intent"
>
Читать пост
</Link>
| Свойство | Описание |
|---|---|
to |
Путь или объект маршрута (router.routes.blog.post). |
params |
Значения динамических сегментов. Типы генерируются автоматически. |
search |
Query-параметры. Можно передать функцию (old) => new. |
hash |
Значение #anchor. |
preload |
'intent' | 'render' | 'viewport' | 'none'. Управляет префетчингом loader/компонента. |
disabled |
Блокирует клик. |
from |
Позволяет строить относительный путь от текущего/родительского маршрута. |
mask |
Оставляет предыдущий маршрут «под» текущим (например, для модальных окон). |
state |
Любые сериализуемые данные, доступные в router.state.location.state. |
preloadGcMaxAge |
TTL в мс, после которого префечнутые данные можно GC. |
activeProps / inactiveProps / pendingProps |
Автоматический merge пропсов в зависимости от состояния ссылки. |
Советы:
to с экспортами, а не со строками: to={router.routes.blog.post.to} — типы params/search гарантированы.from='/dashboard' to='./$tab' — путь останется корректным даже при рефакторинге.<Link to="/settings">{({ isActive, isPending }) => ...}</Link>.preload="viewport" + preloadDelay={200} творит чудеса для списков карточек при скролле.Link есть onClick — не забывайте вызывать event.preventDefault() только при необходимости, иначе сломается навигация.<Link
to="/reports/$id"
params={{ id: row.id }}
preload="intent"
>
{({ isActive, isPending }) => (
<button
className={clsx('btn', isActive && 'btn-primary')}
disabled={isPending}
>
Открыть
</button>
)}
</Link>
<Navigate />Декларативный редирект:
<Navigate to="/login" search={{ from: router.state.location.href }} />
import { useNavigate, redirect } from '@tanstack/react-router'
const navigate = useNavigate()
navigate({ to: '/settings', search: (prev) => ({ ...prev, drawer: true }) })
// С передачей пользовательского состояния
navigate({
to: '/checkout',
state: { fromCart: true, experiment: 'checkout-a' },
})
// Относительно активного маршрута
navigate({
from: '/dashboard',
to: '../reports/$id',
params: { id: reportId },
})
router.navigate({
to: '/blog/$postId',
params: { postId: 123 },
replace: true,
resetScroll: false,
mask: {
to: '/dashboard',
search: true,
},
})
router.navigate({
to: '/photos/$photoId',
params: { photoId },
mask: {
to: router.state.location, // фон остаётся прежним
},
})
Внутри маршрута можно проверять useRouterState({ select: (s) => s.location.mask }) и в зависимости от этого рендерить модалку поверх предыдущего контента.
import { redirect } from '@tanstack/react-router'
export const route = createFileRoute('/profile')({
loader: async () => {
const user = await getUser()
if (!user) {
throw redirect({
to: '/login',
search: { from: '/profile' },
})
}
return user
},
})
replace: true — не добавляет запись в history.resetScroll: true — сбрасывает скролл.from: router.state.location + search: true — переход относительно текущего пути.router.history.block((transition) => { ... }) возвращает функцию unblock — храните её в эффекте.beforeLoad и возвращать () => unblock — удобно для условных блокировок.router.preloadRoute({ to, params, search }) — загружает компонент/loader.preload="intent" — автоматом вызывает preloadRoute при фокусе/hover.preloadDelay (мс) — задержка перед префетчем.router.invalidate() можно вызвать после мутации, чтобы следующий префетч подхватил свежие данные.preload="viewport" с IntersectionObserver, оборачивая Link в компонент, который включает префетч, когда ссылка попадает в область видимости.<Link
activeOptions={{ exact: true }}
activeProps={{ className: 'text-primary' }}
preload="intent"
to="/dashboard/$tab"
params={{ tab: 'users' }}
>
Пользователи
</Link>
const isActive = router.useMatch({
to: '/dashboard/$tab',
params: { tab: 'analytics' },
})
const { status } = useRouterState({ select: (s) => s.status })
const isPendingAnalytics = status === 'pending' && isActive
<Link
to="/reports/$id"
params={{ id }}
inactiveProps={{ className: 'text-muted' }}
pendingProps={{ 'aria-busy': true }}
/>
import { useMatchRoute } from '@tanstack/react-router'
const matchRoute = useMatchRoute()
const match = matchRoute({ to: '/blog/$postId', fuzzy: true })
const cls = match ? 'bg-primary text-white' : 'bg-surface'
router.buildLocation({ to, params, search }) возвращает объект, который можно переиспользовать для <Link {...location}>.router.state.location.state данные, которые не нужно сериализовать в URL (например, рефы или объемные объекты).router.history.back() и проверяйте router.history.canGo(-1) чтобы не уходить на пустую историю.resetScroll: false, чтобы не сбрасывать позицию при мелких шагах.startTransition(() => navigate(...)), чтобы UI оставался отзывчивым (особенно в больших таблицах).lazy/loaderDeps — навигация может переиспользовать данные, если вы грамотно описали зависимости.router.subscribe('onBeforeNavigate', cb) помогает логировать или отменять переходы на уровне всего приложения.router.navigate только после завершения промиса и проверяет router.state.status.router.startTransition() — оборачивает переход в React transition.router.history.block((event) => ...) — глобальный блокировщик (например, при незакрытой форме).useRouterState({ select: (s) => s.status }) — статус idle | pending.router.deferCancel(transition.key) даёт возможность откатить переход вручную (полезно для wizard’ов).useBlocker(({ proceed, reset }) => { ... }) — настраиваемый UX: показывайте кастомный модал, вызывайте proceed() при подтверждении.router.subscribe('onNavigateEnd', ({ status }) => ...) — можно логировать время переходов и статус загрузок.<Link /> вместо <a> для внутренних переходов.preload к страницам с тяжелыми loaders.activeOptions.throw redirect(...).router.navigate в onSuccess.mask, чтобы не терять фон.resetScroll для длинных страниц и пошаговых форм.router.history.block или useBlocker перед потерей несохранённых данных.router.state.status для отображения skeleton’ов при переходе.