Dev Highlights

Доки по разработке

This project is maintained by teniryte

Компоненты навигации

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 пропсов в зависимости от состояния ссылки.

Советы:

Рендер-проп пример

<Link
  to="/reports/$id"
  params={{ id: row.id }}
  preload="intent"
>
  {({ isActive, isPending }) => (
    <button
      className={clsx('btn', isActive && 'btn-primary')}
      disabled={isPending}
    >
      Открыть
    </button>
  )}
</Link>

Декларативный редирект:

<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 },
})

Из вне React

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 }) и в зависимости от этого рендерить модалку поверх предыдущего контента.

Redirect внутри loaders/action

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
  },
})

Управление историей

Prefetch API

Active-состояние ссылок

<Link
  activeOptions={{ exact: true }}
  activeProps={{ className: 'text-primary' }}
  preload="intent"
  to="/dashboard/$tab"
  params={{ tab: 'users' }}
>
  Пользователи
</Link>

Пользовательский hook

const isActive = router.useMatch({
  to: '/dashboard/$tab',
  params: { tab: 'analytics' },
})

const { status } = useRouterState({ select: (s) => s.status })
const isPendingAnalytics = status === 'pending' && isActive

Pending/Inactive props

<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'

Список лайфхаков

Транзишены и блокировка

Чек-лист