Реализация SSR в Next.js

С момента своего создания в 2016 году Next.js продемонстрировал огромный рост и признание в сообществе разработчиков. Это один из самых популярных и, возможно, самый эффективный доступный фреймворк React. Он имеет ключевые функции, такие как встроенная система маршрутизации , возможность писать коды сервера в том же проекте, что и ваш клиент.

В этой статье мы создадим блог о путешествиях, чтобы узнать, как использовать динамическую маршрутизацию как на стороне клиента, так и на стороне сервера в Next.js. Мы также рассмотрим, как страницы должны отображаться в Next.js.

Next.js: среда React со встроенным SSR.

Одна интересная особенность Next.js заключается в том, что вы можете контролировать, как страницы отображаются клиенту индивидуально. Все ваши страницы Next.js визуализируются на сервере, но когда вы используете новую стабильную функцию App Router , вы можете отображать страницы с клиента или сервера. В этой статье мы сосредоточимся на страницах, отображаемых на сервере.

По умолчанию Next.js предварительно визуализирует все ваши страницы (страницы, визуализируемые сервером). Это означает, что Next.js заранее генерирует HTML-код каждой страницы.

Существует два разных способа предварительного рендеринга ваших страниц: генерация статического сайта (SSG) и рендеринг на стороне сервера (SSR).

Что отличает эти методы, так это то, когда генерируются страницы. Например, при использовании SSG страницы генерируются во время сборки, а страницы, использующие SSR, — во время выполнения. Когда мы говорим «время выполнения», это означает, что страницы генерируются при каждом запросе страницы.

Это сильно отличается от SSG, который генерирует страницу только один раз и повторно использует ее для каждого запроса. Причина, по которой страницы SSR перегенерируются при каждом запросе, заключается в том, что они были созданы для страниц, где данные всегда будут меняться. Итак, если у вас есть страница, на которой данные изменяются почти каждый раз, когда пользователь делает запрос на эту страницу, вы можете использовать SSR.

Настройка гибкости с помощью Next.js

В нашем руководстве мы создадим простой блог, чтобы продемонстрировать динамическую маршрутизацию и SSR с использованием Next.js и Agility, автономной системы управления контентом (CMS). Если у вас еще нет Agility, первым шагом в этом руководстве будет создание учетной записи.

Мы просто собираемся настроить необходимое нам содержимое в Agility, а позже мы будем получать это содержимое с помощью Agility Content Fetch JS SDK .

После регистрации вам будет предложено создать новый экземпляр:

Регистрация на Agility CMS

Выберите вариант Next.js Starter . После этого вам необходимо будет назвать экземпляр; выберите любое имя, которое вам нравится.

По умолчанию у вас уже есть список сообщений в блоге, поэтому перейдите в «Содержимое» > «Сообщения в блоге» на левой боковой панели:

Список сообщений в блоге на странице учетной записи Agility

Вы можете добавить больше сообщений или просто использовать значение по умолчанию для этого урока. Теперь, когда у нас настроена учетная запись, давайте получим ключ API нашего экземпляра и сохраним его где-нибудь. Откройте «Настройки» > «Ключи API» на левой боковой панели. Agility предоставляет два ключа API: предварительный просмотр и интерактивный режим. В этом уроке мы будем использовать действующий ключ API, поэтому скопируйте его и сохраните где-нибудь.

Настройка среды разработки Next.js

Чтобы настроить среду разработки, давайте сначала создадим новый проект Next.js. Для этого выполните следующую команду, которая запустит установку последней версии Next.js:

npx create-next@latest

Эта команда вызовет несколько подсказок. В этом руководстве используется JavaScript, но для стилизации мы будем использовать Tailwind CSS, поэтому , когда вас спросят об этом, выберите « Да» . Наконец, если вы не знакомы с использованием src каталога в Next.js, выберите «Нет» в качестве значения для приглашения каталога.

Затем Next.js спросит, хотите ли вы использовать обычный Pages Router или новый App Router. Маршрутизатор страниц просто означает использование традиционного маршрутизатора, в котором все файлы в pagesкаталоге представляют собой маршрут. Маршрутизатор приложений — это новая форма маршрутизатора, в которой для определения маршрута для любого каталога используется специальный файл .

В этом уроке мы будем использовать Pages Router, поскольку App Router не поддерживает SSR. Вместо этого он использует серверные компоненты React (RSC) .

После установки откройте проект в предпочитаемом вами редакторе и создайте файл .env. Это файл, в котором мы сохраним наш API-ключ от Agility, поэтому добавьте его в свой файл .gitignore. Затем сохраните ключ API, который вы скопировали ранее, как AGILITY_API_KEY в вашем файле .env.

Давайте продолжим установку необходимой зависимости, необходимой для извлечения контента из Agility. Выполните следующую команду:

npm install @agility/content-fetch

После установки создайте файл в корневом каталоге. В этом файле мы создадим конфигурацию для подключения нашего проекта к нашему экземпляру Agility. Вставьте в файл следующее:

// agility.lib.js
import agility from '@agility/content-fetch';
const instanceGuid = '';

export const api = agility.getApi({
  guid: instanceGuid,
  apiKey: process.env.AGILITY_API_KEY,
  isPreview: false,
});

Это instanceGuid идентификатор созданного вами экземпляра. Вернитесь на панель управления Agility, и в верхней части той же страницы, где вы получили ключ API, вы найдете раздел GUID экземпляра с рядом символов. Скопируйте и вставьте символы в instanceGuid переменную.

Представляем маршруты Next.js

В отличие от React, где вам необходимо установить внешнюю библиотеку для управления маршрутизацией, Next.js имеет встроенную систему маршрутизации, которая обрабатывает все ваши маршруты.

В этом разделе мы представим краткое введение в маршрутизацию в Next.js, чтобы вы могли следовать этому руководству.

Этот маршрутизатор работает так: любые файлы, и файл, находящийся в каталоге, становится маршрутом. В вашей файловой структуре вы найдете каталог с файлом..tsjs.tsx.jsxpagespagesindex.js

В своем терминале запустите npm run dev. Когда вы откроете локальный URL-адрес приложения, вы увидите, что содержимое файла соответствует тому, что отображается в браузере. Для подтверждения внесите некоторые изменения и сохраните его. Вернитесь в браузер и вы увидите, что изменения были внесены:

Применены изменения маршрута Next.js

Из изображения выше мы можем сделать вывод:

  • Файл каталога представляет корневой маршрут этого каталога.index.js
  • Каталог внутри pagesкаталога становится вложенным маршрутом. Таким образом, файловая структура типа даст маршрутpages/users/profile.js/users/profile
  • Файл можно использовать для нескольких и динамических маршрутов, используя []оператор расширения ( ...). Фигурные скобки обозначают динамический маршрут, а оператор расширения используется для перехвата всех маршрутов этого каталога.

Создание вашей первой страницы Next.js

Чтобы улучшить ваше понимание маршрутизации Next.js, мы сейчас рассмотрим, как создавать страницы и плавно перемещаться между ними.

Сначала давайте обновим содержимое маршрута /, перейдя на него и заменив его кодом ниже:

const Home = () => {
  return (
      <main className={`pb-14 mt-28 max-w-[800px] mx-auto`}>
        <h1 className='font-bold text-3xl mb-4'>Welcome to my blog</h1>
        <p>There are no posts yet</p>
      </main>
  );
};
export default Home;

Теперь давайте создадим новую страницу «О программе» . Перейдите в pagesкаталог и создайте файл. Вставьте код ниже:

const About = () => {
  return (
      <main className={`pb-14 mt-28 max-w-[800px] mx-auto`}>
        <h1 className='font-bold text-3xl mb-4'>Welcome to my about page</h1>
        <p>Learn more about my blog here</p>
      </main>
  );
};
export default About;

Сохраните проект и перейдите в браузер. Это загрузит страницу About.

Далее давайте поработаем над созданием небольшого заголовка, который будет переходить с домашней страницы на страницу «О программе» и наоборот. В корневом каталоге вашего проекта создайте папку components и в ней создайте файл. Теперь вставьте следующее:

import Link from 'next/link';

const Header = () => {
  return (
    <header
      className={`fixed w-full left-0 top-0 bg-blue-500 text-white py-6 px-10 flex items-center justify-between`}
    >
      <h1 className={`font-bold`}>XenTravels</h1>
      <ul className={'flex'}>
        <li>
          <Link
            href={'/'}
            className={
              'text-xs text-gray-200 hover:underline block ml-7 hover:text-white transition-all'
            }
          >
            Home
          </Link>
        </li>
        <li>
          <Link
            href={'/about'}
            className={
              'text-xs text-gray-200 hover:underline block ml-7 hover:text-white transition-all'
            }
          >
            About
          </Link>
        </li>
      </ul>
    </header>
  );
};
export default Header;

Компонент Link используется для навигации по различным страницам вашего приложения Next.js. Он похож на <a> тег в HTML, но имеет больше возможностей. Например, когда вы используете Link компонент на странице, Next.js автоматически выполняет предварительную выборку связанной страницы в фоновом режиме. Это помогает обеспечить плавную навигацию.

В приведенном выше примере теперь мы можем импортировать и использовать Header компонент как в файлах, так и в файлах. Если предположить, что у нас несколько страниц, повторное использование компонента на каждой из них было бы просто излишним. Вместо этого мы можем импортировать и использовать компонент в файле, который является глобальным для всех страниц нашего приложения. Давайте посмотрим на это дальше.

Добавление глобальной панели навигации в компонент приложения Next.js

Файл является глобальным и применяется ко всем страницам, даже к тем, которые мы еще не создали. Давайте воспользуемся этим, интегрировав в него компонент.

Теперь ваш файл должен выглядеть так:

import Header from '@/components/Header';
import '@/styles/globals.css';
export default function App({ Component, pageProps }) {
  return (
    <>
      <Header />
      <Component {...pageProps} />
    </>
  );
}

Результат страницы «О компании»

Понимание динамической маршрутизации в Next.js

Динамическая маршрутизация предполагает наличие «n» количества различного контента со схожей структурой контента. Например, возьмем социальную сеть, где пользователи могут зарегистрироваться и публиковать контент.

Если вы хотите отобразить список пользователей или коллекцию сообщений конкретного пользователя, непрактично создавать отдельный файл для каждого человека. Однако, несмотря на то, что каждый пользователь имеет уникальные данные, структура контента останется прежней — на каждой странице пользователя будет указано имя пользователя, изображение профиля и список его сообщений.

Здесь на помощь приходит динамическая маршрутизация. В Next.js мы используем фигурные скобки []для обозначения динамического маршрута в файловой структуре. Таким образом, файловая структура типа может дать маршрут или в зависимости от обстоятельств. Наличие миллиарда пользователей не изменит файл; все они будут использовать одну и ту же файловую структуру, но каждый из них будет иметь уникальные данные в профиле.pages/users/[username].js/users/elijah/users/elonmusk

Вот шаги к динамической маршрутизации:

  • Вы создаете динамический маршрут, например, для набора пользователей.pages/users/[username].js
  • Когда клиент перейдет на , вы сможете получить параметр запроса с этой страницы./users/elijahusername
  • Используя полученное вами уникальное значение username(в данном случае это elijah), вы можете получить информацию об этом пользователе:

Изменение имени пользователя URL-пути

Универсальные маршруты

Функция перехвата всех маршрутов часто бывает очень полезна в сценариях, когда вы хотите, чтобы все маршруты определенного каталога возвращали одну и ту же страницу. Например, мы видели изображение, где файловая структура, подобная такой, дает URL-путь.pages/posts/[...slug].js/posts/2021/1/10/reactjs

Допустим, мы хотим, чтобы все сообщения в моем блоге извлекались по году, месяцу и дню:

Изменение адресата URL-адреса

Обратите внимание, что веб-страница справа имеет дополнительный маршрут (т. е. /nothing), но не выдает ошибку. Вместо этого он по-прежнему возвращал сообщение в блоге указанного дня (позже мы увидим, как это было сделано).

Next.js использует оператор [...slug].js для возврата всех маршрутов. В этом файле вы можете получить желаемые значения и игнорировать остальные.

Всеобъемлющие маршруты можно сделать необязательными, добавив двойные скобки: pages/posts/[[...slug]].js. Это означает, что хотя маршрут может быть перехвачен , он также может перехватывать и файлы . Позже мы увидим практическое применение этого.

Вложенные динамические сегменты

Динамические сегменты создаются, когда вы заключаете папку в квадратные скобки pages. Вы можете думать об этом как о динамической папке. Например, pages/[username]/posts.js может привести к /elijah/posts или /elonmusk/posts.

В маршруте может быть несколько динамических сегментов. Например, в блоге о путешествиях у вас могут быть страницы pages/categories/[continent]/[country]/[state].js, которые могут содержать /categories/africa/nigeria/lagos

В качестве альтернативы вы можете использовать структуру, подобную рендерингу путей, например pages/posts/[year]/[month]/[day].jsposts/2022/1/11. Этот подход отражает всеохватывающие маршруты, которые мы обсуждали ранее, но с более явной файловой структурой.

Динамические маршруты или статические маршруты

Статические маршруты имеют приоритет над динамическими маршрутами. Рассмотрим папку, такую как pages/posts, содержащую как [slug].js (динамический), так и my-intro-post.js (статический). При переходе к posts/my-intro-post в браузере загружается статический файл. Но для любого маршрута, отличного от “my-intro-post”, загружается динамический файл.

Параметры запроса и динамическая маршрутизация в Next.js

Параметры запроса часто используются для представления параметров строки запроса и параметров динамической маршрутизации. Параметры строки запроса - это параметры строки запроса в URL-адресе. Например, в google.com/search ?q=somesearch, q - это параметр строки запроса, а значение - somesearch.

Когда вы видите параметры запроса в этой статье, мы имеем в виду параметры динамической маршрутизации. Параметры динамической маршрутизации относятся к динамическому маршруту. Например, такой маршрут, как mytravelblog.com/posts/traveling-to-new-york с файловой структурой, подобной posts/[slug].js вернет slug в качестве параметра динамического маршрута со значением traveling-to-new-york. В этом разделе мы увидим, как получить доступ к параметрам запроса в рамках динамического маршрута. Вернитесь в корневой каталог вашего проекта, создайте файл posts.json и вставьте это:

{
  "posts": [
    {
      "id": 1,
      "title": "Exploring the Serene Beaches of Bali",
      "slug": "exploring-the-serene-beaches-of-bali",
      "body": "<p>Bali, the Island of Gods, is renowned for its picturesque beaches and stunning landscapes</p>"
    },
    {
      "id": 2,
      "title": "A Safari Adventure in the Heart of Africa",
      "slug": "a-safari-adventure-in-the-heart-of-africa",
      "body": "<p>Embark on a once-in-a-lifetime safari adventure in the heart of Africa...</p>"
    },
  ]
}

На данный момент мы будем извлекать записи локально из posts.json, а не из Agility. Начните с создания папки blog внутри pages. В этой папке мы создадим два файла: [slug].js и index.js

// blog/index.js
import postsData from 'posts.json';
export default function Blog() {
  const posts = postsData.posts;
  return (
    <main className={`pb-14 mt-28 max-w-[800px] mx-auto`}>
      <ul className={'grid grid-cols-3 gap-x-4 gap-y-8 items-center'}>
        {posts.map((post) => (
          <li key={post.id}>
            <Link
              href={`/blog/${post.slug}`}
              className={
                'block bg-white rounded-md shadow-md transition-all hover:scale-125'
              }
            >
              <span className={'px-5 pb-6 mt-5 block font-medium capitalize'}>
                {post.title}
              </span>
            </Link>
          </li>
        ))}
      </ul>
    </main>
  );
}

В приведенном выше коде мы извлекаем записи непосредственно из posts.json и отображаем их в виде списка для наших пользователей. Теперь давайте динамически отрисуем каждое сообщение из [slug].js:

//blog/[slug].js
import { useRouter } from 'next/router';

export default function PostItem() {
  const { query } = useRouter();
  const [post, setPost] = useState({});
  useEffect(() => {
    if (query?.slug) {
      const post = postsData.posts.find((post) => query.slug === post.slug);
      setPost(post);
    }
  }, [query?.slug]);
  return (
    <main className={'pb-14 mt-28 max-w-[800px] mx-auto'}>
      <div
        className={
          'mt-10 border-b-2 pb-3 border-[#ccc] flex justify-between items-center'
        }
      >
        <h1 className={'font-bold text-3xl capitalize leading-relaxed'}>
          {post.title}
        </h1>
      </div>
      <div
        className={'blog-body mt-10'}
        dangerouslySetInnerHTML={{ __html: post.body }}
      />
    </main>
  );
}

Hook useRouterпредоставляет несколько свойств и методов для доступа ко всем свойствам маршрута и для ручного управления тем, как вы хотите, чтобы система маршрутизации Next.js работала.

Одним из свойств этого хука является параметр запроса, который предоставляет вам доступ к параметру динамического маршрута. В нашем примере выше параметром является slug, потому что мы назвали файл [slug].js. Вот как мы получаем доступ к параметрам запроса в динамических маршрутах — мы используем хук useRouter. Мы рассмотрим, как это работает в SSR, в следующем разделе.

Императивная динамическая маршрутизация с помощью Next.js

До сих пор мы видели только, как использовать этот Link компонент для навигации по различным страницам в Next.js. Есть еще один способ навигации по различным страницам — императивная навигация.

Компонент Link— это декларативный способ перехода на другую страницу в Next.js в то время как метод router.push является обязательным способом. Управление императивом означает, что вы говорите Next.js как он должен перейти на следующую страницу. Например, метод router.push, который находится в перехватчике useRouter, используется для программного перехода на другую страницу:

export default function Dashboard() {
  const router = useRouter();

  useEffect(() => {
    if (!token) return router.push('/login');
  }, []);

  return <></>;
}

Обратите внимание, что router.push не генерирует тег <a>, аналогичный window.location. Следовательно, поисковые роботы могут не обнаружить его, что может нанести ущерб поисковой оптимизации (SEO). Однако в некоторых случаях это может быть желаемым результатом.

Маршруты API в Next.js

Next.js имеет папку api, которая позволяет вам структурировать все маршруты вашего сервера. Структурирование маршрутов вашего сервера в этой папке происходит таким же образом, как если бы вы делали это в клиенте. Это означает, что у вас могут быть динамические маршруты API.

Напомним, что наши посты содержались в файле posts.json. Теперь, вместо того чтобы передавать его непосредственно клиенту, мы можем сделать это через сервер. Перейдите в pages/api и создайте каталог posts. В этом новом каталоге создайте новый файл с именем index.js:

//pages/api/posts/index.js
import postsData from 'posts.json';

export default function handler(req, res) {
  const posts = postsData.posts;
  res.status(200).json(posts);
}

Это работает аналогично тому, как работает сервер Express. Откройте браузер или Postman и отправьте запрос на адрес . Вы получите все свои сообщения из файла./api/postsposts.json

Это всего лишь простой пример с локальными данными. В реальном приложении вы можете извлекать данные из базы данных, такой как MongoDB, вместе с моделями и другими функциями. Итак, это полнофункциональный сервер Node.js.

Следующий маршрут API, который нам понадобится, предназначен для извлечения каждого сообщения, поэтому создайте файл [slug].js:

// pages/api/posts/[slug].js
import postsData from 'posts.json';

export default function handler(req, res) {
  const { slug } = req.query;
  const post = postsData.posts.find((post) => post.slug === slug);
  res.status(200).json(post);
}

При выполнении запроса к этому маршруту API ему необходимо будет передать уникальный пул, как мы видели в клиенте.

Теперь мы можем обновить файлы в каталоге нашего блога, чтобы они извлекались из наших маршрутов API:

// blog/index.js
export default function Blog() {
  useEffect(() => {
    const res = await fetch('http://localhost:3000/api/posts');
    const posts = await res.json()
  }, []);

  return ()
}

// blog/[slug].js
export default function PostItem() {
  useEffect(() => {
    const res = await fetch(`http://localhost:3000/api/posts/${query.slug}`);
    const post = await res.json()
  }, [])

  return ();
}

Получение данных на стороне клиента не очень хорошо подходит для SEO в приложениях Next.js. Но в тех случаях, когда вам необходимо получить данные от клиента, вы можете использовать клиентские библиотеки получения данных, такие как SWR .

Вложенная маршрутизация с параметрами запроса

Вложенная маршрутизация охватывает как несколько динамических сегментов, так и несколько динамических маршрутов. До сих пор мы видели только пример вложенного маршрута с несколькими динамическими сегментами. Теперь давайте посмотрим на пример в действии. В этом примере мы немного выйдем за рамки нашего руководства и воспользуемся JSONPlaceholder .

Мы собираемся получить список сообщений для разных пользователей. Создайте файловую структуру типа pages/users/[userId]/posts.js и вставьте приведенный ниже код в posts.js файл:

//pages/users/[userId]/posts.js

const UserPosts = () => {
  const [posts, setPosts] = useState([]);
  const { query } = useRouter();

  useEffect(() => {
    if (query?.userId) {
      (async () => {
        const res = await fetch(
          `https://jsonplaceholder.typicode.com/posts?userId=${query.userId}&_limit=3`
        );
        const posts = await res.json();
        posts.length >= 1 && setPosts(posts);
      })();
    }
  }, [query?.userId]);

  return (
    <main className={`pb-14 mt-28 max-w-[800px] mx-auto`}>
      <ul className={'grid grid-cols-3 gap-x-4 gap-y-8 items-center'}>
        {posts.map((post) => (
          <li key={post.id}>
            <span className={'px-5 pb-6 mt-5 block font-medium capitalize'}>
              {post.title}
            </span>
          </li>
        ))}
      </ul>
    </main>
  );
};

Параметры запроса и рендеринг на стороне сервера (SSR)

Использование рендеринга на стороне сервера очень полезно, когда у вас есть данные, которые часто меняются. Вот почему Next.js восстанавливает HTML-код страниц, используя SSR, всякий раз, когда к этой странице делается запрос.

В этом разделе мы рассмотрим, как можно использовать SSR с динамической маршрутизацией и как мы можем получить доступ к параметрам запроса внутри файла getServerSideProps. Если вы новичок в SSR, getServerSideProps это функция, которую вы создаете, чтобы указать, что страница должна использовать SSR.

Это работает так: вы создаете функцию на странице, даете ей имя getServerSideProps и экспортируете ее:

export const getServerSideProps = () => {};

Любой код, который вы пишете внутри getServerSideProps функции, выполняется на сервере, и Next.js обычно запускает функцию getServerSideProps перед отрисовкой страницы. Это означает, что вы можете сделать здесь все свои запросы на выборку и подготовить их до того, как они будут отображены клиенту.

Чтобы увидеть это в действии, вернитесь к pages/index.js , создайте функцию getServerSideProps и вставьте в нее следующее:

const posts = await api.getContentList({
  referenceName: 'posts',
  languageCode: 'en-us',
  sort: 'properties.date',
});
return {
  props: {
    posts: posts.items,
  },
};

api импортирован из ../agility.lib.js . Функция возвращает объект props, который будет передан в наш компонент страницы в качестве props:

export default function Home({ posts }) {
  return (
    <div>
      <main className={`pb-14 mt-28 max-w-[800px] mx-auto`}>
        <ul className={'grid grid-cols-3 gap-x-4 gap-y-8 items-center'}>
          {posts.map((post, index) => (
            <PostCard postFields={post.fields} key={index} />
          ))}
        </ul>
      </main>
    </div>
  );
}

То же самое относится и к динамическим маршрутам. Если мы хотим получить доступ к каждой из этих записей, запустите каталог записей и создайте в нем файл [slug].js. Напомним, что у нас уже есть каталог блогов, в который записи загружаются локально. Теперь мы хотим извлечь данные из нашего экземпляра Agility:

// pages/posts/[slug].js

export const getServerSideProps = async (context) => {
  const { slug } = context.query;
  const posts = await api.getContentList({
    referenceName: 'posts',
    languageCode: 'en-us',
  });

  const post = posts.items?.find((post) => post.fields.slug === slug);

  return {
    props: {
      post: post.fields,
    },
  };
};

const PostItem = ({ post }) => {
  return (
    <main className={'pb-14 mt-28 max-w-[800px] mx-auto'}>
      <div
        className={
          'mt-10 border-b-2 pb-3 border-[#ccc] flex justify-between items-center'
        }
      >
        <h1
          className={
            'font-bold text-3xl capitalize leading-relaxed max-w-[500px]'
          }
        >
          {post.title}
        </h1>
        <span className={'text-xs text-[#aaa]'}>
          {new Date(post.date).toDateString()}
        </span>
      </div>
      <div
        className={'blog-body mt-10'}
        dangerouslySetInnerHTML={{ __html: post.content }}
      />
    </main>
  );
};
export default PostItem;

Поскольку мы получаем информацию с сервера, мы не можем использовать useRouter хук. Но он getServerSideProps предоставляет context параметр, который имеет свойства маршрута страницы, включая query. Этот метод облегчает получение динамических данных по динамическому маршруту с использованием SSR.

Обработка распространенного варианта использования динамической маршрутизации в Next.js

До сих пор мы видели множество распространенных примеров использования динамических сегментов и маршрутов. В этом разделе мы рассмотрим распространенный вариант использования параметров строки запроса для фильтрации сообщений. Но вместо использования параметров строки запроса мы будем использовать необязательный всеобъемлющий маршрут.

Направляйтесь к index.js в каталоге pages и переименуйте его [[...filter]].js:

export const getServerSideProps = async ({ query }) => {
  const posts = await api.getContentList({
    referenceName: 'posts',
    languageCode: 'en-us',
    sort: 'properties.date',
  });

  if (query?.filter) {
    const [year, month] = query.filter;
    const filteredPosts = posts.items.filter(({ fields: post }) => {
      const date = new Date(post.date);
      if (date.getFullYear() === +year) {
        if (month && date.getMonth() + 1 === +month) return post;
        else if (!month) return post;
      }
    });

    return {
      props: {
        posts: filteredPosts,
      },
    };
  }

  return {
    props: {
      posts: posts.items,
    },
  };
};

export default function Home({ posts }) {
  return (
    <main className={`pb-14 mt-28 max-w-[800px] mx-auto`}>
      <ul className={'grid grid-cols-3 gap-x-4 gap-y-8 items-center'}>
        {posts.map((post, index) => (
          <PostCard postFields={post.fields} key={index} />
        ))}
      </ul>
    </main>
  );
}

Теперь, когда вы перейдете к /2022, вы получите все записи за 2022 год, а /2022/9 отобразит все записи за сентябрь 2022 года:

Последняя демонстрация блога о путешествиях

Заключение

В этой статье мы углубились в динамическую маршрутизацию как на стороне клиента, так и на стороне сервера, а также изучили вложенную маршрутизацию и параметры запросов с помощью SSR. Решая, какие страницы вашего приложения должны использовать SSR, а какие — SSG, подумайте, хотите ли вы, чтобы страница предварительно отображалась во время сборки или во время выполнения.

Страницы, использующие SSR, предварительно обрабатываются во время выполнения, что не идеально для SEO. С другой стороны, страницы, использующие SSG, предварительно обрабатываются во время сборки, что часто отлично подходит для SEO.

Обладая этими знаниями, вы должны быть хорошо подготовлены к созданию полнофункционального веб-приложения, как мы продемонстрировали в этой статье с использованием Agility CMS.