정적 트윗 — Twitter를 삽입하는 더 좋은 방법

Twitter는 생각과 콘텐츠를 공유할 수 있는 좋은 방법입니다. 하지만 현실을 직시합시다. 플랫폼의 사용 편의성에도 불구하고 임베드 기능은 매우 번거롭습니다. 트윗 삽입은 다음을 의미합니다.
  • 페이지가 로드됩니다. 트윗은 어디에도 보이지 않습니다.
  • 페이지 로드 후 트윗 위젯 JS가 로드됩니다.
  • iframe이 초기화되어 더 많은 JS가 시작됩니다. 페이지 콘텐츠가 이동하여 공간을 만듭니다.
  • 전체 웹 보기가 iframe 내부에 렌더링됩니다. 더 많은 페이지 레이아웃 전환.

  • 포함된 트윗은 페이지 로드가 완료된 후 몇 초 후에 로드되는 경우가 많기 때문에 이것은 수준 이하의 경험입니다. 트윗과 같이 정적인 것(여전히 편집 버튼을 기다리고 있음)의 경우 포함 프로세스가 매우 역동적이라는 것은 매우 아이러니합니다. 정적 트윗에 대한 정적 임베드가 없는 이유는 무엇입니까?

    대신 단순히 트윗 이미지를 삽입하는 것을 제안할 수 있습니다. 그러나 이미지도 로드 속도가 느리고 리트윗이나 좋아요와 같은 트윗 통계가 이미지에서 오래될 수 있습니다.

    몇 줄의 코드로 다음과 같은 최신 통계로 매번 즉시 로드되는 React 구성 요소를 만들 수 있습니다.



    NextJS, Tailwind CSS 및 Twitter의 API를 사용하여 몇 가지 간단한 단계로 이 작업을 수행하는 방법을 살펴보겠습니다.

    트윗 디자인하기



    트위터에 내장된 도구를 피하고 있기 때문에 트윗도 직접 디자인해야 합니다. Tailwind CSS는 유틸리티 우선 접근 방식으로 이를 매우 쉽게 수행할 수 있습니다.

    기본 둥근 사각형으로 시작하여 무작위 트윗을 참조로 사용하여 HTML 요소에 스타일을 추가할 수 있습니다. 나중에 우리는 이 구성 요소를 모든 트윗과 함께 작동하도록 동적으로 만들 것입니다.

    You can experiment with an interactive version of this component on 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>
    


    Twitter의 API에서 트윗 가져오기



    위의 트윗 구성 요소를 동적이고 재사용 가능하게 만들려면 Twitter의 API를 사용하여 ID로 트윗을 가져오고 응답을 구문 분석하고 트윗 정보를 구성 요소에 전달해야 합니다.

    이를 위해서는 에 등록할 Twitter 계정이 필요합니다. 등록이 완료되면 프로젝트를 생성하고 애플리케이션에 설정할 Bearer 토큰을 얻습니다. 이 예에서는 Bearer 토큰이 환경 변수로 설정되고 process.env.TWITTER_TOKEN 를 사용하여 가져온다고 가정합니다.

    Twitter의 를 참조하여 쿼리 매개변수로 트윗 ID를 엔드포인트/2/tweets에 전달하고 응답으로 트윗 데이터 배열을 수신합니다. 페이지에 트윗을 표시하는 데 필요한 콘텐츠에 대해 이 데이터를 구문 분석할 수 있습니다. 우리는 이 함수가 트윗 ID 배열을 문자열로 받아 다음 단계에서 구현할 것입니다.

    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로 전달할 수 있습니다. 이렇게 하면 페이지 로드 후 브라우저에서 데이터를 가져올 필요가 없습니다. 대신 웹 페이지 자체와 함께 로드되고 단순히 우리 구성 요소 내에서 소비됩니다.

    따라서 Twitter 내장 iframe을 교체하기 위해 트윗 데이터를 가져와서 캐싱하고 정적 콘텐츠로 전달할 수 있습니다. 또한 트윗 데이터는 빌드 시에만 가져오기 때문에 Twitter의 API에 대한 호출도 줄어듭니다.

    NextJS는 getStaticProps를 사용하여 이 전체 프로세스를 쉽게 만듭니다.

    NextJS에서 생성된 페이지 구성 요소가 있다고 가정합니다. 이 함수를 추가하면 빌드 시 가져올 데이터를 정의할 수 있고 페이지 구성 요소에 대한 정적 소품으로 제공됩니다. 이 함수에 트윗 ID 배열을 전달하기만 하면 됩니다.

    export default function Index({ tweets }) {
      // {...}
    }
    
    export async function getStaticProps() {
      const tweets = await getTweets(['1516188493541785606'])
      return {
        props: {
          tweets,
        },
      }
    }
    


    마지막으로 페이지 구성 요소에서 결과tweets prop을 사용할 수 있습니다. 참조된 각 트윗을 StaticTweet 소품의 데이터와 일치시키는 데 도움이 되는 tweets 함수를 만든 다음 해당 데이터를 이전에 만든 Tweet UI 구성 요소에 전달해 보겠습니다.

    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에서 볼 수 있습니다.

    좋은 웹페이지 즐겨찾기