Next.js — это популярный фреймворк на основе React для создания быстрых и масштабируемых веб-приложений. Он предоставляет множество готовых функций, таких как рендеринг на стороне сервера и создание статических сайтов, что делает его идеальным для создания веб-сайтов, ориентированных на контент. На самом деле мы можем создать веб-сайт, используя Next.js, который извлекает статьи из канала Medium RSS. Без лишних слов, продолжайте читать ниже!

Начиная

Для начала нам нужно получить URL-адрес RSS-канала публикации Medium или пользователя, от которого мы хотим отображать статьи. Medium предоставляет RSS-канал для каждой публикации или пользователя, к которому мы можем получить доступ, добавив /feed в конце публикации или URL-адреса пользователя. Например, RSS-канал моего среднего блога находится по адресу https://medium.com/@kevin-jonathan/feed. Получив URL-адрес RSS-канала, мы можем использовать Next.js, чтобы получить данные из API и начать показывать статьи на нашем собственном веб-сайте.

Получение RSS-канала (с помощью JSON)

Удобно то, что мы можем использовать this для получения наших данных из RSS-канала. Таким образом, нам не нужно использовать пакет xml2js npm для ручного анализа RSS в json.

Формат примерно такой: https://api.rss2json.com/v1/api.json?rss_url=https://medium.com/feed/@kevin-jonathan

Не стесняйтесь вместо этого изменить запрос rss_url на RSS-канал вашего собственного носителя.

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

И что теперь?

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

Давайте просто создадим что-то действительно простое в нашем компоненте статьи. Это исходный код. Создайте новый файл с именем «articles.js» и поместите код ниже.

export default function Articles() {
    return (
        <section>
            <div>
                <h3>Latest Articles</h3>
                <ul>
                    <div>
                        <a href="#" target={"_blank"}>
                            <h3>Title</h3>
                        </a>
                    </div>
                </ul>
                <a
                    href={""}
                    target={"_blank"}
                    rel={"noopener noreferrer"}
                >
                    Read More on Medium
                </a>
            </div>
        </section>
    );
}

И не забудьте указать ссылку на компонент в вашем index.js.

import Articles from "../components/articles.js";

export default function Home() {
  return (
    <div>
      <Head>
        <title>Website Title</title>
        <meta name="description" content="Generated by create next app" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <main>
        <Articles />
      </main>
    </div>
  );
}

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

Для извлечения данных мы можем использовать rss2json API, указанный выше, и использовать `useEffect` и `useState` реакции.

import { useEffect, useState } from 'react';

export default function Articles() {
  const [items, setItems] = useState([]);
  const [error, setError] = useState(null);
  
  useEffect(() => {
        async function fetchData() {
            try {
                const res = await fetch('https://api.rss2json.com/v1/api.json?rss_url=https://medium.com/feed/@kevin-jonathan');
                const data = await res.json();
                const items = data.items;
                setItems(items);
            } catch {
                setError(true);
            }
        }

        fetchData();
    }, []);
  ...
}

Подожди, что это за коды? так много внеземных языков выше! Не волнуйтесь, я объясню о частях одну за другой.

const [items, setItems] = useState([]);
const [error, setError] = useState(null);

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

useEffect(() => {
    // The logic here
}, []);

Как насчет `useEffect`? на самом деле это довольно новое в React, и мне было трудно выразить смысл словами. Но в основном вы сообщаете React, что ваш компонент должен что-то сделать после рендеринга. React запомнит переданную вами функцию (мы будем называть ее нашим «эффектом») и вызовет ее позже после выполнения обновлений DOM.

Надеюсь, что до сих пор вы все еще понимаете, о чем я говорю. Я мог бы понять, если бы некоторые из вас не поняли, потому что я был таким 3 года назад. Но я все равно продолжу объяснять!

useEffect(() => {
    async function fetchData() {
        try {
            const res = await fetch('https://api.rss2json.com/v1/api.json?rss_url=https://medium.com/feed/@kevin-jonathan');
            const data = await res.json();
            const items = data.items;
            setItems(items);
        } catch {
            setError(true);
        }
    }

    fetchData();
}, []);

Логическая идея в приведенном выше коде довольно проста. Мы пытаемся получить данные из API, ожидая ресурса, и содержат его для анализа в JSON и установки элементов в состоянии элементов. Если выборка не удалась, перехватите ошибку и сохраните ее в состоянии ошибки.

Хотите знать, почему мы должны получать «data.items» вместо данных? Это изображение может говорить само за себя:

Проще говоря, данные списка статей, которые мы хотим получить, содержатся в массиве «items» в JSON.

Отображение статей

После получения данных мы хотим отобразить их в пользовательском интерфейсе.

return (
    <section>
        <div>
            <h3>Latest Articles</h3>
            <ul>
                {items.map((item, index) => (
                    <div key={index}>
                        <a href={item.link} target={"_blank"}>
                            <h3>{item.title}</h3>
                        </a>
                    </div>
                ))}
            </ul>
            <a
                href={"https://kevin-jonathan.medium.com/"}
                target={"_blank"}
                rel={"noopener noreferrer"}
            >
                Read More on Medium
            </a>
        </div>
    </section>
);

И что это опять?

{items.map((item, index) => (
     <div key={index}>
            <a href={item.link} target={"_blank"}>
            <h3>{item.title}</h3>
            </a>
     </div>
))}

По сути, мы говорим нашему приложению реагировать на сопоставление состояния данных элементов с каждым отдельным элементом и соответствующим образом отображать каждый элемент. Следует отметить, что часть key={index} важна, если вы хотите избежать предупреждений от ESLint.

Обработка ошибок

Что если произойдет сбой API или нашему приложению не удастся получить данные из API? Это было бы большой катастрофой? нет?

Мы можем поймать ошибку, когда нам не удалось получить данные, и показать резервный пользовательский интерфейс после завершения обработки!

Добавьте этот код, чтобы отобразить резервный пользовательский интерфейс на тот случай, если наше приложение обнаружит ошибку API:

// Put this above our actual UI code, right above the return
if (error) {
    return (
        <section>
            <div>
                <h3>Latest Articles</h3>
                <ul>
                    <p>Failed to fetch data, please try again later.</p>
                </ul>
                <a
                    href={"https://kevin-jonathan.medium.com/"}
                    target={"_blank"}
                    rel={"noopener noreferrer"}
                >
                    Read on Medium
                </a>
            </div>
        </section>
    );
}

return (
    <section>
    ...

Вот полный код:

import { useEffect, useState } from 'react';

export default function Articles() {
    const [items, setItems] = useState([]);
    const [error, setError] = useState(null);

    useEffect(() => {
        async function fetchData() {
            try {
                const res = await fetch('https://api.rss2json.com/v1/api.json?rss_url=https://medium.com/feed/@kevin-jonathan');
                const data = await res.json();
                const items = data.items.slice(0, 3);
                setItems(items);
            } catch {
                setError(true);
            }
        }

        fetchData();
    }, []);

    if (error) {
        return (
            <section>
                <div>
                    <h3>Latest Articles</h3>
                    <ul>
                        <p>Failed to fetch data, please try again later.</p>
                    </ul>
                    <a
                        href={"https://kevin-jonathan.medium.com/"}
                        target={"_blank"}
                        rel={"noopener noreferrer"}
                    >
                        Read on Medium
                    </a>
                </div>
            </section>
        );
    }

    return (
        <section>
            <div>
                <h3>Latest Articles</h3>
                <ul>
                    {items.map((item, index) => (
                        <div key={index}>
                            <a href={item.link} target={"_blank"}>
                                <h3>{item.title}</h3>
                            </a>
                        </div>
                    ))}
                </ul>
                <a
                    href={"https://kevin-jonathan.medium.com/"}
                    target={"_blank"}
                    rel={"noopener noreferrer"}
                >
                    Read More on Medium
                </a>
            </div>
        </section>
    );
}

Вот как это выглядит на моем веб-сайте (хотя я добавил некоторые стили):

Ссылка на article.js в моем репозитории (коды сильно отличаются, потому что я реализовал в нем TailwindCSS и дополнительные функции. Не стесняйтесь проверить его, если вам интересно узнать о стиле):



Заключение

В этой статье мы узнали, как отображать статьи Medium на сайте Next.js с помощью RSS-канала. Мы можем использовать rss2json, чтобы упростить процесс разбора RSS, а также использовать useState и useEffect для обработки выборки и сохранения данных и отображения данных в пользовательском интерфейсе.

Надеюсь, эта статья поможет вам разработать приложение Next.js с перечислением в нем ваших последних статей! Если вы хотите дать мне отзыв или задать любой вопрос, не стесняйтесь оставить его в комментарии ниже. Спасибо за чтение!