Статические твиты — лучший способ внедрения Twitter

Twitter — это отличный способ поделиться мыслями и контентом. Но давайте посмотрим правде в глаза — несмотря на простоту использования платформы, ее функция встраивания чрезвычайно громоздка. Встраивание твита означает:

  1. Страница загружается. Твиты нигде не видны.
  2. Виджет твита JS загружается после загрузки страницы.
  3. Инициализируется iframe, что приводит к появлению еще большего количества JS. Содержимое страницы смещается, чтобы освободить место.
  4. Внутри iframe отображается целая веб-страница. Еще больше смещается макет страницы.

Это не самый лучший опыт, поскольку встроенные твиты часто загружаются через несколько секунд после завершения загрузки страницы. Довольно иронично, что для такой статичной вещи, как твит (все еще жду кнопку редактирования), процесс встраивания настолько динамичен. Почему бы не иметь статичную вставку для статичных твитов?

Можно было бы предложить просто встраивать изображения твитов — однако изображения также медленно загружаются, а статистика твита, такая как ретвиты или лайки, на изображении будет неактуальной.

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

Давайте посмотрим, как это сделать всего за несколько простых шагов, используя NextJS, Tailwind CSS и API Twitter.

Дизайн твита

Поскольку мы обходимся без встроенного инструмента Twitter, нам также необходимо создать твит самостоятельно. Tailwind CSS позволяет сделать это очень просто благодаря своему подходу, ориентированному на полезность.

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

Вы можете поэкспериментировать с интерактивной версией этого компонента на Tailwind Play.

<div class="relative flex min-h-screen flex-col justify-center">
  <div class='bg-gray-100 border border-slate-300 rounded-2xl duration-300 my-8 p-5 max-w-xl mx-auto'>
      <div class='flex justify-between'>
        <a class='flex items-center gap-3 group' href='https://twitter.com/naval/status/1516188493541785606'>
          <img
            class='rounded-full h-12 w-12'
            src='https://pbs.twimg.com/profile_images/1256841238298292232/ycqwaMI2_400x400.jpg'
          />
          <div class='flex flex-col leading-snug'>
            <span class='text-sm font-semibold flex gap-2'>
              Naval
              <span class='text-sm font-normal opacity-70 group-hover:opacity-100 duration-300'>@naval</span>
            </span>
            <span class='text-sm opacity-80 group-hover:opacity-100 duration-300'>April 18, 2022</span>
          </div>
        </a>
      </div>
      <div class='text-lg my-3 leading-normal'>
        Your success in life depends on your ability to make good decisions.Your happiness depends on your ability to not care about the outcomes.
      </div>
      <div class='flex mt-2 gap-6 text-sm font-medium tracking-wider'>
        <span>20 Replies</span>
        <span>6190 Retweets</span>
        <span>32.9K Likes</span>
      </div>
    </div>
</div>
Вход в полноэкранный режим Выход из полноэкранного режима

Получение твитов из API Twitter

Чтобы сделать компонент твитов динамичным и многократно используемым, нам понадобится API Twitter для получения любого твита по ID, разбора ответа и передачи информации о твите в компонент.

Для этого вам понадобится учетная запись Twitter для регистрации на сайте developer.twitter.com. После регистрации вы создадите проект и получите токен Bearer для установки в вашем приложении. В данном примере предполагается, что токен Bearer установлен как переменная окружения и извлекается с помощью process.env.TWITTER_TOKEN.

Ссылаясь на документацию API Twitter, мы передадим идентификаторы твитов в конечную точку /2/tweets в качестве параметров запроса и получим в ответ массив данных твитов. Мы можем разобрать эти данные для получения только того содержимого, которое нам нужно для отображения наших твитов на странице. Эта функция будет принимать массив идентификаторов твитов в виде строк, которые мы реализуем в следующем шаге.

export const fetchTweets = async (tweetIds = []) => {
  if (tweetIds.length === 0) return []

  const options = '&expansions=author_id&tweet.fields=public_metrics,created_at&user.fields=profile_image_url'

  const response = await fetch(
    `https://api.twitter.com/2/tweets/?ids=${tweetIds.join(',')}${options}`,
    { headers: { Authorization: `Bearer ${process.env.TWITTER_TOKEN}` } }
  )
  const body = await response.json()
  const tweets = body.data.map((t) => {
    const author = body.includes.users.find((a) => a.id === t.author_id)
    return {
      id: t.id,
      text: t.text,
      createdAt: new Date(t.created_at).toLocaleDateString('en', {
        year: 'numeric',
        month: 'long',
        day: 'numeric',
        timeZone: 'UTC',
      }),
      metrics: {
        replies: formatMetric(t.public_metrics?.reply_count ?? 0),
        likes: formatMetric(t.public_metrics?.like_count ?? 0),
        retweets: formatMetric(t.public_metrics?.retweet_count ?? 0),
      },
      author: {
        name: author.name,
        username: author.username,
        profileImageUrl: author.profile_image_url,
      },
      url: `https://twitter.com/${author.username}/status/${t.id}`,
    }
  })

  return tweets
}

export const formatMetric = (number) => {
  if (number < 1000) {
    return number
  }
  if (number < 1000000) {
    return `${(number / 1000).toFixed(1)}K`
  }
  return `${(number / 1000000).toFixed(1)}M`
}

Вход в полноэкранный режим Выход из полноэкранного режима

Рендеринг на стороне сервера с помощью NextJS

Наконец, нам нужно использовать нашу API-функцию на странице, отображающей твиты.

Секрет мгновенной загрузки страницы заключается в SSR — рендеринге на стороне сервера. Для веб-страниц, отображающих статический контент, мы можем кэшировать данные, на основе которых работает веб-страница, и предоставлять их вместе с HTML/CSS. Таким образом, данные не нужно извлекать из браузера после загрузки страницы. Вместо этого они загружаются вместе с самой веб-страницей и просто потребляются нашими компонентами.

Таким образом, вместо iframe, встроенного в Twitter, мы можем получать и кэшировать данные твитов и предоставлять их в виде статического контента. Это также сократит количество обращений к API Twitter, поскольку данные твита будут извлекаться только во время сборки.

NextJS упрощает весь этот процесс с помощью getStaticProps.

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

export default function Index({ tweets }) {
  // {...}
}

export async function getStaticProps() {
  const tweets = await getTweets(['1516188493541785606'])
  return {
    props: {
      tweets,
    },
  }
}
Войти в полноэкранный режим Выйти из полноэкранного режима

И наконец, мы можем использовать полученный реквизит tweets в нашем компоненте страницы. Давайте создадим функцию StaticTweet, которая поможет сопоставить каждый твит с его данными в реквизите tweets, а затем передадим эти данные в пользовательский компонент Tweet, который мы создали ранее.

import Head from 'next/head'
import Tweet from 'components/Tweet'
import { fetchTweets } from 'lib/fetchTweets'

export default function Home({ tweets }) {
  const StaticTweet = ({ id }) => {
    const tweet = tweets.find((tweet) => tweet.id === id)
    return <Tweet tweet={tweet} />
  }

  return (
    <div>
      <Head>
        <title>Static Tweets</title>
      </Head>

      <main className='container max-w-4xl py-8'>
        <h1 className='font-bold text-4xl text-center'>Static Tweets</h1>
        <StaticTweet id='1516188493541785606' />
      </main>
    </div>
  )
}

export async function getStaticProps() {
  const tweets = await fetchTweets(['1516188493541785606'])
  return {
    props: {
      tweets,
    },
  }
}
Вход в полноэкранный режим Выход из полноэкранного режима

И мы закончили! Статический рендеринг твитов, сгенерированных на стороне сервера, мгновенно загружается вместе с остальным содержимым веб-страницы.

Рабочая демонстрация этого кода доступна на GitHub.

Оцените статью
devanswers.ru
Добавить комментарий