Ссылки и навигация
Маршрутизатор Next.js позволяет выполнять переходы между страницами на стороне клиента, аналогично одностраничному приложению.
Для этого предоставляется React-компонент под названием Link
.
import Link from 'next/link'
function Home() {
return (
<ul>
<li>
<Link href="/">Главная</Link>
</li>
<li>
<Link href="/about">О нас</Link>
</li>
<li>
<Link href="/blog/hello-world">Пост в блоге</Link>
</li>
</ul>
)
}
export default Home
В приведённом выше примере используется несколько ссылок. Каждая из них сопоставляет путь (href
) с известной страницей:
/
→pages/index.js
/about
→pages/about.js
/blog/hello-world
→pages/blog/[slug].js
Любой <Link />
в области просмотра (изначально или при прокрутке) будет предварительно загружен по умолчанию (включая соответствующие данные) для страниц, использующих статическую генерацию (Static Generation). Данные для серверного рендеринга (server-rendered) загружаются только при клике на <Link />
.
Ссылки на динамические пути
Вы также можете использовать интерполяцию для создания пути, что удобно для динамических сегментов маршрута. Например, для отображения списка постов, переданных компоненту в качестве пропса:
import Link from 'next/link'
function Posts({ posts }) {
return (
<ul>
{posts.map((post) => (
<li key={post.id}>
<Link href={`/blog/${encodeURIComponent(post.slug)}`}>
{post.title}
</Link>
</li>
))}
</ul>
)
}
export default Posts
В примере используется
encodeURIComponent
для поддержки UTF-8 в пути.
Альтернативно, используя URL-объект:
import Link from 'next/link'
function Posts({ posts }) {
return (
<ul>
{posts.map((post) => (
<li key={post.id}>
<Link
href={{
pathname: '/blog/[slug]',
query: { slug: post.slug },
}}
>
{post.title}
</Link>
</li>
))}
</ul>
)
}
export default Posts
Теперь вместо интерполяции для создания пути мы используем URL-объект в href
, где:
pathname
— имя страницы в директорииpages
. В данном случае/blog/[slug]
.query
— объект с динамическим сегментом. В данном случаеslug
.
Доступ к маршрутизатору
Для доступа к router
объекту в React-компоненте вы можете использовать useRouter
или withRouter
.
В целом мы рекомендуем использовать useRouter
.
Императивная навигация
next/link
должен покрывать большинство ваших потребностей в маршрутизации, но вы также можете выполнять навигацию на стороне клиента без него, ознакомьтесь с документацией по next/router
.
Следующий пример показывает, как выполнять базовую навигацию по страницам с помощью useRouter
:
import { useRouter } from 'next/router'
export default function ReadMore() {
const router = useRouter()
return (
<button onClick={() => router.push('/about')}>
Нажмите, чтобы узнать больше
</button>
)
}
Поверхностная маршрутизация (Shallow Routing)
Примеры
Поверхностная маршрутизация позволяет изменять URL без повторного выполнения методов получения данных, включая getServerSideProps
, getStaticProps
и getInitialProps
.
Вы получите обновлённые pathname
и query
через router
объект (добавленный useRouter
или withRouter
), без потери состояния.
Для включения поверхностной маршрутизации установите опцию shallow
в true
. Рассмотрим следующий пример:
import { useEffect } from 'react'
import { useRouter } from 'next/router'
// Текущий URL — '/'
function Page() {
const router = useRouter()
useEffect(() => {
// Всегда выполняйте навигацию после первого рендера
router.push('/?counter=10', undefined, { shallow: true })
}, [])
useEffect(() => {
// Счётчик изменился!
}, [router.query.counter])
}
export default Page
URL обновится до /?counter=10
, и страница не будет заменена, изменится только состояние маршрута.
Вы также можете отслеживать изменения URL через componentDidUpdate
, как показано ниже:
componentDidUpdate(prevProps) {
const { pathname, query } = this.props.router
// убедитесь, что пропсы изменились, чтобы избежать бесконечного цикла
if (query.counter !== prevProps.router.query.counter) {
// загрузите данные на основе нового запроса
}
}
Ограничения
Поверхностная маршрутизация работает только для изменений URL на текущей странице. Например, предположим, что у нас есть другая страница pages/about.js
, и вы выполняете:
router.push('/?counter=10', '/about?counter=10', { shallow: true })
Поскольку это новая страница, текущая страница будет выгружена, загружена новая и ожидаться получение данных, несмотря на запрос поверхностной маршрутизации.
При использовании поверхностной маршрутизации с middleware не гарантируется, что новая страница соответствует текущей, как это было ранее без middleware. Это связано с тем, что middleware может динамически переписывать маршруты, что нельзя проверить на стороне клиента без загрузки данных, которая пропускается при поверхностной маршрутизации, поэтому изменение поверхностного маршрута всегда должно рассматриваться как поверхностное.
Динамические маршруты
Динамические маршруты позволяют добавлять пользовательские параметры в URL. Узнайте, как создавать динамические маршруты.
Пользовательское приложение (Custom App)
Управляйте инициализацией страниц и добавьте общий макет для всех страниц, переопределив стандартный компонент App, используемый в Next.js.