Связывание и навигация
В Next.js существует четыре способа навигации между маршрутами:
- Использование компонента
<Link>
- Использование хука
useRouter
(Клиентские компоненты) - Использование функции
redirect
(Серверные компоненты) - Использование нативного History API
На этой странице мы рассмотрим, как использовать каждый из этих вариантов, и углубимся в принципы работы навигации.
Компонент <Link>
<Link>
— это встроенный компонент, который расширяет HTML-тег <a>
для обеспечения предварительной загрузки и клиентской навигации между маршрутами. Это основной и рекомендуемый способ навигации между маршрутами в Next.js.
Вы можете использовать его, импортировав из next/link
и передав проп href
компоненту:
import Link from 'next/link'
export default function Page() {
return <Link href="/dashboard">Dashboard</Link>
}
import Link from 'next/link'
export default function Page() {
return <Link href="/dashboard">Dashboard</Link>
}
Существуют другие необязательные пропсы, которые можно передать в <Link>
. Подробнее см. в справочнике API.
Примеры
Ссылки на динамические сегменты
При ссылках на динамические сегменты можно использовать шаблонные строки и интерполяцию для генерации списка ссылок. Например, для генерации списка постов блога:
import Link from 'next/link'
export default function PostList({ posts }) {
return (
<ul>
{posts.map((post) => (
<li key={post.id}>
<Link href={`/blog/${post.slug}`}>{post.title}</Link>
</li>
))}
</ul>
)
}
Проверка активных ссылок
Для определения активной ссылки можно использовать usePathname()
. Например, чтобы добавить класс к активной ссылке, можно проверить, совпадает ли текущий pathname
с href
ссылки:
'use client'
import { usePathname } from 'next/navigation'
import Link from 'next/link'
export function Links() {
const pathname = usePathname()
return (
<nav>
<ul>
<li>
<Link className={`link ${pathname === '/' ? 'active' : ''}`} href="/">
Главная
</Link>
</li>
<li>
<Link
className={`link ${pathname === '/about' ? 'active' : ''}`}
href="/about"
>
О нас
</Link>
</li>
</ul>
</nav>
)
}
'use client'
import { usePathname } from 'next/navigation'
import Link from 'next/link'
export function Links() {
const pathname = usePathname()
return (
<nav>
<ul>
<li>
<Link className={`link ${pathname === '/' ? 'active' : ''}`} href="/">
Главная
</Link>
</li>
<li>
<Link
className={`link ${pathname === '/about' ? 'active' : ''}`}
href="/about"
>
О нас
</Link>
</li>
</ul>
</nav>
)
}
Прокрутка к id
Поведение по умолчанию в App Router Next.js — прокрутка к верху нового маршрута или сохранение позиции прокрутки при навигации назад и вперед.
Если вы хотите прокрутить к определенному id
при навигации, можно добавить к URL хеш-ссылку с #
или передать хеш-ссылку в проп href
. Это возможно, поскольку <Link>
рендерится как элемент <a>
.
<Link href="/dashboard#settings">Настройки</Link>
// Вывод
<a href="/dashboard#settings">Настройки</a>
Полезно знать:
- Next.js прокрутит к странице, если она не видна в области просмотра при навигации.
Отключение восстановления прокрутки
Поведение по умолчанию в App Router Next.js — прокрутка к верху нового маршрута или сохранение позиции прокрутки при навигации назад и вперед. Если вы хотите отключить это поведение, можно передать scroll={false}
в компонент <Link>
или scroll: false
в router.push()
или router.replace()
.
// next/link
<Link href="/dashboard" scroll={false}>
Dashboard
</Link>
// useRouter
import { useRouter } from 'next/navigation'
const router = useRouter()
router.push('/dashboard', { scroll: false })
Хук useRouter()
Хук useRouter
позволяет программно изменять маршруты из клиентских компонентов.
'use client'
import { useRouter } from 'next/navigation'
export default function Page() {
const router = useRouter()
return (
<button type="button" onClick={() => router.push('/dashboard')}>
Dashboard
</button>
)
}
Полный список методов useRouter
см. в справочнике API.
Рекомендация: Используйте компонент
<Link>
для навигации между маршрутами, если у вас нет особых причин использоватьuseRouter
.
Функция redirect
Для серверных компонентов используйте функцию redirect
.
import { redirect } from 'next/navigation'
async function fetchTeam(id: string) {
const res = await fetch('https://...')
if (!res.ok) return undefined
return res.json()
}
export default async function Profile({ params }: { params: { id: string } }) {
const team = await fetchTeam(params.id)
if (!team) {
redirect('/login')
}
// ...
}
import { redirect } from 'next/navigation'
async function fetchTeam(id) {
const res = await fetch('https://...')
if (!res.ok) return undefined
return res.json()
}
export default async function Profile({ params }) {
const team = await fetchTeam(params.id)
if (!team) {
redirect('/login')
}
// ...
}
Полезно знать:
- По умолчанию
redirect
возвращает статус 307 (Временное перенаправление). При использовании в серверном действии возвращается 303 (Смотрите в другом месте), что обычно используется для перенаправления на страницу успеха после POST-запроса.redirect
внутренне выбрасывает ошибку, поэтому его следует вызывать вне блоковtry/catch
.redirect
можно вызывать в клиентских компонентах во время рендеринга, но не в обработчиках событий. Вместо этого можно использовать хукuseRouter
.redirect
также принимает абсолютные URL и может использоваться для перенаправления на внешние ссылки.- Если вы хотите выполнить перенаправление до процесса рендеринга, используйте
next.config.js
или Middleware.
Подробнее см. в справочнике API redirect
.
Использование нативного History API
Next.js позволяет использовать нативные методы window.history.pushState
и window.history.replaceState
для обновления истории браузера без перезагрузки страницы.
Вызовы pushState
и replaceState
интегрируются в роутер Next.js, позволяя синхронизироваться с usePathname
и useSearchParams
.
window.history.pushState
Используйте для добавления новой записи в историю браузера. Пользователь может вернуться к предыдущему состоянию. Например, для сортировки списка товаров:
'use client'
import { useSearchParams } from 'next/navigation'
export default function SortProducts() {
const searchParams = useSearchParams()
function updateSorting(sortOrder: string) {
const params = new URLSearchParams(searchParams.toString())
params.set('sort', sortOrder)
window.history.pushState(null, '', `?${params.toString()}`)
}
return (
<>
<button onClick={() => updateSorting('asc')}>Сортировать по возрастанию</button>
<button onClick={() => updateSorting('desc')}>Сортировать по убыванию</button>
</>
)
}
'use client'
import { useSearchParams } from 'next/navigation'
export default function SortProducts() {
const searchParams = useSearchParams()
function updateSorting(sortOrder) {
const params = new URLSearchParams(searchParams.toString())
params.set('sort', sortOrder)
window.history.pushState(null, '', `?${params.toString()}`)
}
return (
<>
<button onClick={() => updateSorting('asc')}>Сортировать по возрастанию</button>
<button onClick={() => updateSorting('desc')}>Сортировать по убыванию</button>
</>
)
}
window.history.replaceState
Используйте для замены текущей записи в истории браузера. Пользователь не сможет вернуться к предыдущему состоянию. Например, для переключения локали приложения:
'use client'
import { usePathname } from 'next/navigation'
export function LocaleSwitcher() {
const pathname = usePathname()
function switchLocale(locale: string) {
// Например, '/en/about' или '/fr/contact'
const newPath = `/${locale}${pathname}`
window.history.replaceState(null, '', newPath)
}
return (
<>
<button onClick={() => switchLocale('en')}>Английский</button>
<button onClick={() => switchLocale('fr')}>Французский</button>
</>
)
}
'use client'
import { usePathname } from 'next/navigation'
export function LocaleSwitcher() {
const pathname = usePathname()
function switchLocale(locale) {
// Например, '/en/about' или '/fr/contact'
const newPath = `/${locale}${pathname}`
window.history.replaceState(null, '', newPath)
}
return (
<>
<button onClick={() => switchLocale('en')}>Английский</button>
<button onClick={() => switchLocale('fr')}>Французский</button>
</>
)
}
Как работают маршрутизация и навигация
App Router использует гибридный подход для маршрутизации и навигации. На сервере код вашего приложения автоматически разделяется на части по сегментам маршрутов. А на клиенте Next.js предварительно загружает и кэширует сегменты маршрутов. Это означает, что при переходе пользователя на новый маршрут браузер не перезагружает страницу, и повторно рендерятся только измененные сегменты маршрутов — что улучшает опыт навигации и производительность.
1. Разделение кода (Code Splitting)
Разделение кода позволяет разбить код приложения на меньшие части для загрузки и выполнения браузером. Это уменьшает объем передаваемых данных и время выполнения каждого запроса, что повышает производительность.
Серверные компоненты позволяют автоматически разделять код приложения по сегментам маршрутов. Это означает, что при навигации загружается только код, необходимый для текущего маршрута.
2. Предварительная загрузка (Prefetching)
Предварительная загрузка — это способ загрузить маршрут в фоновом режиме до того, как пользователь посетит его.
В Next.js есть два способа предварительной загрузки маршрутов:
- Компонент
<Link>
: Маршруты автоматически предварительно загружаются, когда они появляются в области просмотра пользователя. Предварительная загрузка происходит при первой загрузке страницы или при прокрутке. router.prefetch()
: ХукuseRouter
можно использовать для программной предварительной загрузки маршрутов.
Поведение предварительной загрузки по умолчанию для <Link>
(когда проп prefetch
не указан или равен null
) различается в зависимости от использования loading.js
. Предварительно загружается и кэшируется только общий макет вниз по "дереву" рендерящихся компонентов до первого файла loading.js
на 30s
. Это снижает затраты на загрузку всего динамического маршрута и позволяет показать мгновенное состояние загрузки для лучшей визуальной обратной связи пользователям.
Вы можете отключить предварительную загрузку, установив проп prefetch
в false
. Альтернативно, можно предварительно загрузить полные данные страницы за пределами границ загрузки, установив проп prefetch
в true
.
Подробнее см. в справочнике API <Link>
.
Полезно знать:
- Предварительная загрузка не работает в режиме разработки, только в продакшене.
3. Кэширование
Next.js имеет клиентский кэш в памяти под названием Router Cache. Когда пользователи перемещаются по приложению, полезная нагрузка React Server Component для предварительно загруженных сегментов маршрутов и посещенных маршрутов сохраняется в кэше.
Это означает, что при навигации кэш повторно используется по максимуму вместо выполнения новых запросов к серверу — что улучшает производительность, сокращая количество запросов и объем передаваемых данных.
Узнайте больше о том, как работает Router Cache и как его настроить.
4. Частичный рендеринг (Partial Rendering)
Частичный рендеринг означает, что на клиенте повторно рендерятся только измененные сегменты маршрутов при навигации, а общие сегменты сохраняются.
Например, при переходе между двумя родственными маршрутами /dashboard/settings
и /dashboard/analytics
будут рендериться страницы settings
и analytics
, а общий макет dashboard
сохранится.

Без частичного рендеринга каждая навигация вызывала бы полный перерендер страницы на клиенте. Рендеринг только изменяющихся сегментов сокращает объем передаваемых данных и время выполнения, что повышает производительность.
5. Мягкая навигация (Soft Navigation)
Браузеры выполняют "жесткую навигацию" при переходе между страницами. App Router Next.js обеспечивает "мягкую навигацию" между страницами, гарантируя, что повторно рендерятся только измененные сегменты маршрутов (частичный рендеринг). Это позволяет сохранять состояние React на клиенте во время навигации.
6. Навигация назад и вперед
По умолчанию Next.js сохраняет позицию прокрутки при навигации назад и вперед и повторно использует сегменты маршрутов в Router Cache.
7. Маршрутизация между pages/
и app/
При постепенной миграции с pages/
на app/
роутер Next.js автоматически обрабатывает жесткую навигацию между ними. Для обнаружения переходов из pages/
в app/
используется клиентский фильтр роутера, который использует вероятностную проверку маршрутов приложения, что иногда может приводить к ложным срабатываниям. По умолчанию такие случаи должны быть очень редкими, так как мы настраиваем вероятность ложного срабатывания на уровне 0.01%. Эту вероятность можно настроить с помощью опции experimental.clientRouterFilterAllowedRate
в next.config.js
. Важно отметить, что снижение вероятности ложных срабатываний увеличит размер сгенерированного фильтра в клиентском бандле.
Альтернативно, если вы предпочитаете полностью отключить эту обработку и управлять маршрутизацией между pages/
и app/
вручную, можно установить experimental.clientRouterFilter
в false
в next.config.js
. При отключении этой функции любые динамические маршруты в pages, которые пересекаются с маршрутами app, по умолчанию не будут корректно обрабатываться при навигации.