next/link и навигация в Next.js

Next.js предоставляет несколько способов навигации: компонент Link для декларативной навигации, хук useRouter для программной и функции redirect/permanentRedirect для серверной.

Link это основной способ навигации. Он рендерит тег <a>, но перехватывает клик и выполняет клиентскую навигацию без полной перезагрузки:

import Link from 'next/link'

export default function Navigation() {
  return (
    <nav>
      <Link href="/docs">База знаний</Link>
      <Link href="/problems">Задачи</Link>
      <Link href="/roadmap">Роадмап</Link>
    </nav>
  )
}

Prefetching

По умолчанию Link prefetch'ит страницу, когда она попадает в viewport. Это делает переходы мгновенными:

// Prefetch включен по умолчанию
<Link href="/docs/next/ssg">SSG в Next.js</Link>

// Отключить prefetch для редко посещаемых страниц
<Link href="/settings" prefetch={false}>Настройки</Link>

Для статических роутов prefetch загружает весь RSC Payload. Для динамических загружается до ближайшего loading.tsx.

Динамические href

<Link href={`/docs/${doc.slug}`}>
  {doc.title}
</Link>

// С объектом
<Link
  href={{
    pathname: '/problems',
    query: { difficulty: 'hard' }
  }}
>
  Сложные задачи
</Link>

Активная ссылка

Для подсветки текущей страницы используй usePathname:

'use client'

import Link from 'next/link'
import { usePathname } from 'next/navigation'

export function NavLink({
  href,
  children
}: {
  href: string
  children: React.ReactNode
}) {
  const pathname = usePathname()
  const isActive = pathname === href

  return (
    <Link
      href={href}
      className={isActive ? 'text-blue-600 font-bold' : 'text-neutral-600'}
    >
      {children}
    </Link>
  )
}

useRouter

Для программной навигации в клиентских компонентах:

'use client'

import { useRouter } from 'next/navigation'

export function LoginButton() {
  const router = useRouter()

  const handleLogin = async () => {
    const result = await login()

    if (result.success) {
      router.push('/dashboard')
    }
  }

  return <button onClick={handleLogin}>Войти</button>
}

Методы useRouter

МетодОписание
router.push(url)Навигация к URL (добавляет в историю)
router.replace(url)Навигация без добавления в историю
router.back()Назад по истории
router.forward()Вперед по истории
router.refresh()Обновляет текущий роут (перезапрашивает данные с сервера)
router.prefetch(url)Предзагрузка роута

Важно:

useRouter из next/navigation (App Router) и useRouter из next/router (Pages Router) это разные хуки с разным API. В App Router нет router.query, вместо него используй useSearchParams.

Серверная навигация

В серверных компонентах и Server Actions используй redirect:

// В Server Action
'use server'

import { redirect } from 'next/navigation'

export async function createProblem(formData: FormData) {
  const problem = await db.problem.create({ ... })
  redirect(`/problems/${problem.id}`)
}

// В серверном компоненте
import { redirect } from 'next/navigation'

export default async function Page() {
  const user = await getUser()
  if (!user) redirect('/auth/login')

  return <Dashboard user={user} />
}

useSearchParams

Для работы с query-параметрами:

'use client'

import { useSearchParams } from 'next/navigation'

export function FilterPanel() {
  const searchParams = useSearchParams()
  const difficulty = searchParams.get('difficulty')

  return <p>Фильтр: {difficulty || 'все'}</p>
}

usePathname

Для получения текущего пути:

'use client'

import { usePathname } from 'next/navigation'

export function Breadcrumbs() {
  const pathname = usePathname()
  const segments = pathname.split('/').filter(Boolean)

  return (
    <nav>
      {segments.map((segment, i) => (
        <span key={i}>{segment}</span>
      ))}
    </nav>
  )
}

Полезные ресурсы

Связанные темы