Фронтенд: чтение и отображение данных

В этой части статьи вы увидите, как великолепно работают вместе Strapi и NextJS. Вот где они демонстрируют свою силу!

Получение данных

Сначала мы напишем функцию, которая будет получать данные из нашей CMS. В корневом каталоге создайте новую папку lib и в ней файл service.js. Этот файл будет отвечать за выборку данных из CMS. Я использую для этого axios. Если вам больше нравится библиотека fetch, продолжайте и используйте ее.

// lib/service.js
import axios from 'axios';
const fetchFromCMS = async (path) => {
  const url = `http://localhost:1337/${path}`;
  const res = await axios.get(url);
  return res.data;
};
export default fetchFromCMS;

Таким образом, мы в основном просто выполняем запросы GET к нашей CMS, извлекая элементы. Мы должны иметь возможность получать все из нашего файла index.js. Посмотрим, как это сделать.

Отображение данных

Что делает NextJS таким хорошим, так это его способность отображать материалы на стороне сервера. Таким образом мы будем отображать элементы нашего портфолио.

getStaticProps() — предпочтительный способ получения статических данных из CMS. В нашем файле index.js мы импортируем нашу новую функцию выборки и реализуем getStaticProps():

// pages/index.js
// .....
import fetchFromCMS from '../lib/service';
export default function Home({ portfolioItems }) {
  console.log(portfolioItems);
  // ....
}
export async function getStaticProps() {
  const portfolioItems = await fetchFromCMS('portfolios');
  return {
    props: { portfolioItems },
    revalidate: 1,
  };
}

Мы получаем данные из нашей функции fetchFromCMS() и передаем их в качестве аргумента в главную функцию. Это происходит автоматически. Свойство revalidate в основном сообщает Next.js, как часто он должен регенерировать эту страницу и данные. Если вы установите его в 30, то он будет перестраиваться каждые 30 секунд. Это означает, что новые записи не будут видны до тех пор, пока приложение не перестроится. Это довольно круто. Это означает, что мы подаем клиенту чистый HTML, js и CSS. Без извлечения базы данных. Это сделает сайт быстрым.

Кроме того, функция getStaticProps() работает на стороне сервера, в то время как главная функция работает на стороне клиента. Симпатично.

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

Фронтенд: чтение и отображение данных

Безумно круто! Давайте визуализируем это в нашем компоненте React:

// pages/index.js
// ...
export default function Home({ portfolioItems }) {
  return (
    <Layout>
      <div className="entries">
        <div className="row justify-content-start ">
          {portfolioItems.map((portfolio) => (
            <div className="col-md-6">
              <div className="entry mb-3">
                <div className="main-image">
                  <Image
                    src={portfolio.image.name}
                    width={600}
                    height={400}
                    alt={portfolio.Headline}
                  />
                  <h1>{portfolio.Headline}</h1>
                </div>
              </div>
            </div>
          ))}
        </div>
      </div>
    </Layout>
  );
}
// ....

Мы перебираем элементы портфолио, как мы делали это с элементами-заполнителями. Обратите внимание, что мы больше не используем тег <img />.

NextJS предлагает лучший вариант! Их недавно выпущенный компонент React сгенерирует файл в формате .webp из вашего изображения, что приведет к его более быстрой загрузке. Он также поставляется с включенной отложенной загрузкой, и будет адаптивным! Если я правильно понял, обязательные поля width и height принимают значения max-width и max-height.

Однако компонент изображения немного строгий. Вы не можете неявно добавлять изображения извне приложения без внесения URL-адреса в белый список. Итак, что нам нужно сделать дальше — это создать файл конфигурации в нашем корневом каталоге next.config.js и поместить в него следующее:

// config.next.js

module.exports = {
  images: {
    domains: ['images.unsplash.com'],
  },
};

Next.js будет жаловаться и даст вам точный URL, который вы должны ввести. В этом случае, я занесу в белый список URL Unsplash. Потрясающе. Вам нужно перезапустить приложение.

Фронтенд: чтение и отображение данных

Мы получили все данные, и разместили все как надо. Вы удивлены? Я пошел дальше и создал еще несколько элементов портфолио:

Фронтенд: чтение и отображение данных

Просмотр отдельных элементов портфолио

Готовы к еще одному волшебству? Мы должны сделать наши элементы портфолио кликабельными. Когда вы нажимаете на элемент, вы попадаете на страницу этого элемента. На нашей странице index.js мы используем встроенный в Next.js компонент Link. Он работает так же, как и react-router. Мы завернем наши элементы в компонент:

// pages/index.js
import Link from 'next/link';
// ....
export default function Home({ portfolioItems }) {
  return (
    <Layout>
      <div className="entries">
        <div className="row justify-content-start  ">
          {portfolioItems.map((portfolio) => (
            <div className="col-md-6">
              <div className="entry mb-3">
                <Link as={`/portfolio/${portfolio.slug}`} href="/portfolio/[id]"> // this gets added 
                  <div className="main-image">
                    <Image
                      src={portfolio.image.name}
                      width={600}
                      height={400}
                      alt={portfolio.Headline}
                    />
                    <h1>{portfolio.Headline}</h1>
                  </div>
                </Link> // this gets added
              </div>
            </div>
          ))}
        </div>
      </div>
    </Layout>
  );
}
// ....

Если вы попытаетесь нажать на какой-либо из элементов, вы попадете на страницу элемента, которую мы создали ранее. Давайте посмотрим, как мы можем заполнить её правильными данными.

В нашем [slug] .js мы собираемся использовать две специальные серверные функции. getStaticProps(), с которой мы уже знакомы, и getStaticPaths), которая будет строить динамические маршруты во время сборки.

// pages/portfolio/[slug].jsx
// ....
export async function getStaticProps({ params }) {
  const portfolio = await fetchFromCMS(`portfolios?slug=${params.slug}`);
return {
    props: { portfolio: portfolio[0] },
    revalidate: 1,
  };
}

getStaticProps() очень похожа на ту, которая находится в индексном файле, за исключением того, что мы выбираем один элемент по имени ярлыка портфолио, который мы создали в Strapi. Это массив, поэтому мы передадим данные с индексом 0 в клиентскую функцию.

// pages/portfolio/[slug].jsx
// ....
export async function getStaticPaths() {
  const portfolios = await fetchFromCMS('portfolios');
return {
    paths: portfolios.map((portfolio) => ({
      params: {
        slug: portfolio.slug,
      },
    })),
    fallback: false,
  };
}
// ....

Это будет использовано во время сборки. Она извлекает все портфолио и создает URL из имени slug. Мы сможем получать статические страницы вместо того, чтобы каждый раз запрашивать данные у базы данных. Обратите внимание, что мы использовали revalidate в функции getStaticProps(). Скорее всего, вы захотите установить его на что-то большее, чем 1 в производстве, в противном случае это вроде как сбивает всю цель.

Теперь мы можем использовать переданный аргумент в нашей клиентской функции. Весь [slug].jsx теперь выглядит так:

// pages/portfolio/[slug].js
import Image from 'next/image';
import Layout from '../../components/Layout';
import fetchFromCMS from '../../lib/service';
const PortfolioItem = ({ portfolio }) => {
  return (
    <Layout>
      <div className="row">
        <div className="portfolio-image text-center mb-4">
          <div className="col-md-12">
            <Image
              src={portfolio.image.name}
              width={1000}
              height={500}
            />
          </div>
        </div>
      </div>
      <div className="row">
        <div className="portfolio-content">
          <div className="col-md-12">
            <div className="portfolio-headline text-center m-2">
              <h1>{portfolio.Headline}</h1>
            </div>
            <div dangerouslySetInnerHTML={{ __html: portfolio.content }}/>
          </div>
        </div>
      </div>
    </Layout>
  );
};
export async function getStaticPaths() {
  const portfolios = await fetchFromCMS('portfolios');
return {
    paths: portfolios.map((portfolio) => ({
      params: {
        slug: portfolio.slug,
      },
    })),
    fallback: false,
  };
}
export async function getStaticProps({ params }) {
  const portfolio = await fetchFromCMS(`portfolios?slug=${params.slug}`);
return {
    props: { portfolio: portfolio[0] },
    revalidate: 1,
  };
}
export default PortfolioItem;

И если вы попробуете:

Фронтенд: чтение и отображение данных

Данные отображаются правильно!

Данные представлены в формате Markdown. Чтобы их правильно отформатировать, вам нужно использовать какой-то парсер Markdown. Что вы можете сделать, так это добавить новый файл в вашу папку lib с функцией, которая обрабатывает текстовое содержимое, прежде чем вы передадите его клиентской функции. Например:

// lib/processMarkdown.js
import remark from 'remark';
import html from 'remark-html';

// process markdown to html and return
const processMarkdown = async (markdown) => {
  const process = await remark()
    .use(html, {sanitize: true})
    .process(markdown.content);

  return process.toString();
};

export default processMarkdown;

Это было весело. Я надеюсь, что это было так же весело, как и писать это руководство. Next.js и Strapi — потрясающая комбинация и моя технология для создания быстрых и надежных динамических веб-сайтов. А что лучше всего?

Фронтенд: чтение и отображение данных

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

И что самое лучшее? Всё легко настраивается. Плюс ко всему — это открытый исходный код. Вы можете сделать так, чтобы он выглядел именно так, как вы хотите. Он также пользуется большой поддержкой сообщества и самих Strapi.

То же самое можно сказать и о Next.js. Это невероятно удобная штука для создания высокоэффективных веб-сайтов, которые выводят динамический контент (который ведет себя как статический). И его очень легко развернуть. Я рекомендую разместить ваше приложение NextJS на Vercel. Поддержка со стороны ребят из NextJS тоже отличная.

Мы использовали Bootstrap 5, но лишь поверхностно. Если хотите, я всегда могу написать об этом в блоге. Однако самое замечательное в Bootstrap 5 — это то, что он больше не поставляется с jQuery, что, на мой взгляд, является очень хорошим решением команды Bootstrap.

Репозиторий проекта:

https://github.com/Devalo/create-portfolio-with-next-strapi

Была ли эта страница полезной?