Алексей Баранов

Обо мне

Cover Image for Добавляем пагинацию в статический блог на Next.js

Добавляем пагинацию в статический блог на Next.js

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

Процесс можно разделить на несколько этапов:

Результат можно посмотреть в самом низу страницы с постами.

Разделение логики страницы на динамическую и статическую

Мне не хотелось менять структуру страниц сайта, поэтому я решил что страницу буду прокидывать через query string.

Статические страницы в Next.js имеют ряд ограничений при работе с query string. По сути, единственный доступный в моём случае способ получить доступ к параметрам из URL - воспользоваться хуком useSearchParams из клиентского компонента.

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

import { Suspense } from "react";

export default function PostsPage() {
  const posts = getAllPostsMeta();
  const tags = getAllTags();

  return (
    <>
      // ...
      <Suspense fallback={<StaticPosts posts={posts} tags={tags} />}>
        <DynamicPosts posts={posts} tags={tags} />
      </Suspense>
      // ...
    </>
  );
}

Заметьте что компонент DynamicPosts обёрнут в Suspense. Фоллбек будет отрендерен в build-time. А компонент DynamicPosts будет отрендерен уже во время исполнения кода страницы на клиенте.

"use client"

// ...

const DynamicPage: React.FC<Props> = ({ posts, tags }) => {
  const searchParams = useSearchParams();

  const page = Number(searchParams.get("page")) || 1;
  const maxPage = Math.ceil(posts.length / POSTS_PER_PAGE);

  const pageOffset = (page - 1) * POSTS_PER_PAGE;

  const pagePosts = posts.slice(pageOffset, pageOffset + POSTS_PER_PAGE);

  if (!pagePosts.length) return notFound();

  return (
    <>
      <Posts posts={pagePosts} title={"Посты"} withFilter tags={tags} />
      <PageSelector page={page} maxPage={maxPage} />
    </>
  );
};

Для навигационного компонента, будем использовать компонент Link из встроенного пакета next/link и прокидывать в параметр href необходимую нам страницу.

<Link href={`./?page=${page}`}>{page}</Link>

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

Навигационный компонент

Работа над поисковой выдачей

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

Добавление ссылки на каноническую страницу

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

<link rel="canonical" href="https://alexeybaranov.dev/posts" />

В Next.js есть специальное Metadata API, которое можно использовать как раз для этих целей.

Воспользуемся им:

export const metadata: Metadata = {
  title: "Посты | Алексей Баранов. Блог",
  description: "Страница со всеми опубликованными постами",
  alternates: {
    canonical: `/posts`,
  },
};

Добавление директивы Clean-Param в robots.txt

Яндекс поддерживает специальную директиву Clean-param в файлах robots.txt.

Давайте добавим её:

User-agent: Yandex
Clean-param: page
Allow: /

На этом всё! 🎉

Подписывайтесь на мой Youtube канал, Telegram и на сообщество Вконтакте 🙂

В живую результат статьи можно увидеть ниже 🙂

Поделиться

Вам может быть интересно:

Cover Image for Добавляем поиск по тегам в статический блог на Next.js

Добавляем поиск по тегам в статический блог на Next.js

Количество постов растёт, находить их становится сложнее, поэтому я решил добавить поиск по тегам...

Cover Image for Подключение счётчика Яндекс Метрики к Next.js приложению

Подключение счётчика Яндекс Метрики к Next.js приложению

Рассказ о том как я счётчик Яндекс Метрики к блогу подключал...