Фреймворк Next.js динамично развивается, он сделал огромный скачок вперед, и поэтому многие предыдущие статьи о нем могли устареть. На момент написания этой статьи действует версия 10.2.3. Предлагаю заглядывать в документацию при использовании примеров, так как некоторые рекомендации могут устаревать из-за улучшившегося API.
Появился функционал, о котором вы можете не знать
У тех из вас, кто давно использует Next.js, в проектах наверняка накопился огромный объем кода, и вы просто продолжаете писать его в уже сложившемся стиле. Одни делают это в силу привычки, другие — потому что используют свою кодовую базу в качестве каталога фрагментов кода и примеров. Поэтому они рискуют упустить из виду новые крутые функциональные возможности.
Перенаправления сервера и статус «не найдено»
Эти функциональные возможности, как и предыдущие, появились в версии 10. Однако до сих пор возникает много вопросов о том, как сделать перенаправление на сервере. Рекомендую первым делом проверить, используете ли вы современные методы получения данных, потому что только они обновляются и получают новые функциональные возможности.
Вот простой способ сделать перенаправление или показать страницу 404:
// Перенаправление
export function getServerSideProps() {
return {
redirect: {
destination: '/',
permanent: false,
},
}
}
// Страница 404
export function getServerSideProps() {
return {
notFound: true,
}
}
Автоматическое разрешение параметра href
Попробуйте найти в своем проекте next/link
, где есть href
, а также свойство as
. Нашли? Тогда пора обновить эти ссылки. Потому что, начиная с версии 10.x, больше не нужно передавать оба эти параметра. Удалите параметр href
и переименуйте as
в href
: работать будет так же хорошо.
import Link from 'next/link'
// Как было
function MyComponent() {
return (
<Link href="/posts/[post]" as="/posts/blog-post">
Blog post
</Link>
)
}
// Начиная с версии v10.x
function MyComponent() {
return <Link href="/posts/blog-post">Blog post</Link>
}
Функции маршрутизатора клиента
Заметил, что люди часто используют router.push
из useRouter
. Тоже это делаете в функциях, обернутых в useCallback
, или просто внутри useEffect
? Тогда придется упомянуть об этом в зависимостях, как в следующем примере:
// pages/params.jsx
import { useEffect, useCallback } from 'react'
import { useRouter } from 'next/router'
function MyComponent() {
const { push } = useRouter()
const handleClick = useCallback(() => {
// какая-то логика
push('/profile')
}, [push])
useEffect(() => {
if (...) {
push('/sign-in')
}
}, [push])
return <>...</>
}
Но это совершенно необязательно, потому что эти функции не обновляются через повторные отображения, зато правила ESLint будут вынуждать вас это делать. Решения здесь довольно простые: использовать функции маршрутизации из Router
. Это сделает ваш код чище и приятнее. 😉
// pages/params.jsx
import Router from 'next/router'
function MyComponent() {
const handleClick = useCallback(() => {
// какая-то логика
Router.push('/profile')
}, [])
useEffect(() => {
if (...) {
Router.push('/sign-in')
}
}, [])
return <>...</>
}
Иногда при работе с маршрутизатором нужно получить текущее имя пути. Но у react/router
в этом поле хранится динамическое представление маршрутизатора, и оно совпадает с полем маршрутизатора. Тогда создаем эти параметры самостоятельно помощью asPath
. Я сделал обертку поверх useRouter
и всегда имею доступ к свойствам, когда они мне нужны.
// lib/router.js
import { useRouter as useNextRouter } from 'next/router'
export function useRouter() {
const router = useNextRouter()
const [pathname, queryString = ''] = router.asPath.split('?')
return Object.assign(router, { pathname, queryString })
}
Обертка предоставляет удобные свойства, которые используются в ситуации, когда нужно обновить текущий маршрут.
// pages/params.jsx
import Router from 'next/router'
import { useRouter } from 'lib/router'
function MyComponent() {
const { query, pathname } = useRouter()
function handleSubmit(evt) {
const params = new FormData(evt.currentTarget).getAll("fruits");
evt.preventDefault();
Router.replace(
{ pathname, query: { ...query, params }},
null,
{ shallow: true }
)
}
return (
<form>
{...}
<button type="submit">Apply</button>
</form>
)
}
А знаете, почему второй параметр в Router.replace
имеет значение null
? Начиная с версии 10.x, благодаря автоматическому разрешению есть возможность этот параметр пропустить.
Имея такую функциональную возможность, как автоматическое разрешение, было бы естественно задействовать ее в next/router
, но это маленько неудобно в API. Ведь, когда требуется передать опции options
, следует передавать динамический маршрут в первый аргумент и полный путь во второй в более ранних версиях, а в Next.js эти три аргумента сохранялись для обратной совместимости. Хорошо, что есть небольшие удобные функции, которые упрощают использование функций маршрутизатора:
// lib/router.js
import NextRouter from 'next/router'
function push(url, opts) {
return NextRouter.push(url, null, opts)
}
const Router = {
...NextRouter,
push,
}
export default Router
// pages/params.jsx
import Router, { useRouter } from 'lib/router'
function MyComponent() {
const { query } = useRouter()
function handleSubmit(evt) {
const params = new FormData(evt.currentTarget).getAll("fruits");
evt.preventDefault();
Router.push({ pathname, query: { ...query, params } }, { shallow: true });
}
return <>{...}</>
}
Заключение
Спасибо, что дочитали статью до конца. Полный код найдете на GitHub. Всегда есть способ улучшить хорошие инструменты. А небольшие улучшения способны здорово помочь разработчику и его проекту.
Читайте также:
- Получение общих данных в Next.js одним запросом
- Маршрутизация и получение данных в Next.js
- Создаем собственный блог с помощью Next.js и Strapi
Читайте нас в Telegram, VK и Яндекс.Дзен
Перевод статьи Pavel Mineev: An Overview on the Current State of Next.js Router