Front-end

Netflix 클론코딩 기록 남기기 (8) - useSWR을 통한 데이터 불러오기

kjyook 2023. 11. 7. 22:49
728x90

넷플릭스를 내가 만들어야 한다고 생각하면 떠오르는 건 수많은 미디어들의 섬네일, 제목 등이 담긴 컴포넌트들이 가장 먼저 떠올랐다. 영상에 관한 정보들은 서버에 저장이 되어있을 것이고 나는 그러면 이 정보들을 서버에서 꺼내와서 활용해야 한다. 이를 지원하는 React Hooks로 useSWR이라는 swr전략 내의 함수가 존재한다. 아래는 swr에 대한 공식 문서이다.

 

https://swr.vercel.app/ko

 

데이터 가져오기를 위한 React Hooks – SWR

SWR is a React Hooks library for data fetching. SWR first returns the data from cache (stale), then sends the fetch request (revalidate), and finally comes with the up-to-date data again.

swr.vercel.app

 

import useSWR from 'swr';
import fetcher from '@/lib/fetcher';

const useBillboard = () => {
    const { data, error, isLoading } = useSWR('/api/random', fetcher, {
        revalidateIfStale: false,
        revalidateOnFocus: false,
        revalidateOnReconnect: false
    });

    return {
        data,
        error,
        isLoading
    }
};

export default useBillboard;

 

나는 위 공식문서를 보면서 위와 같이 코드를 작성하였다. 여기서는 useSWR을 통해 데이터를 받기만 하고 사용은 다른 컴포넌트 혹은 함수에서 할 것이니까 여기에는 별다른 코드는 작성하지 않았다.

data 에는 fetcher가 로드한 데이터, error에는 fetcher가 던진 에러(혹은 undefined), isLoading은 데이터가 아직 로드중인지 를 알려줍니다.

useSWR 함수는 key, fetcher, option을 파라미터로 받는다. key는 요청을 위한 고유한 키로 인자로써 fetcher로 전달되고 fetcher 는 데이터를 반환하는 비동기 함수이다. 여기서 받은 데이터가 data에 저장된다. 마지막은 option필드로 여러 가지 내용을 다룰 수 있다.

제가 option 필드에 작성한 내용은 마운트 시 오래된 데이터가 존재할 경우 SWR이 갱신해야 할 여부를 제어하는 코드입니다. false이기 때문에 갱신하지 않습니다. 이 option에 작성한 코드는 useSWRImmutable 이라는 hook을 제공하는데 이와 기능이 동일합니다.

 

useSWR(key, fetcher, {
  revalidateIfStale: false,
  revalidateOnFocus: false,
  revalidateOnReconnect: false
})
 
// 다음과 동일
useSWRImmutable(key, fetcher)

 

이제는 이렇게 불러온 데이터를 컴포넌트에서 활용해 봅시다. 이때 주의해야 할 점은 data가 항상 로드되어 있는 것은 아닐 수 있으니 ? 를 같이 활용해 주는 것이 편합니다.

또한 저는 해당 컴포넌트가 로드되는 동안 Title, description, background가 모두 data가 로드되어야 나오는 상황이였지만 button은 data와 상관없이 로드될 수 있었기에 버튼이 먼저 화면에 등장하고 data가 로딩된 후에 나머지 요소들이 화면에 등장하는 등 어색함을 느낄 수 있어서 isLoading을 활용하여 컴포넌트를 구성하였습니다.

 

import useBillboard from "@/hooks/useBillboard";
import React from "react";
import { AiOutlineInfoCircle } from "react-icons/ai";

const Billboard = () => {
    const { data, isLoading } = useBillboard();

    return (
        <div className="relative h-[56.25vw]">
            <video
                className="w-full h-[56.25vw] object-cover brightness-[60%]"
                autoPlay
                muted
                loop
                poster={data?.thumbnalUrl}
                src={data?.videoUrl}>

            </video>
            <div className="absolute top-[30%] md:top-[40%] ml-4 md:ml-16">
                <p className="
                text-white 
                text-1xl 
                md:text-5xl 
                h-tull 
                w-[50%] 
                lg:text-6xl 
                font-bold 
                drop-shadow-xl
                ">
                    {data?.title}
                </p>
                <p className="
                text-white 
                text-[8px] 
                md:text-lg 
                mt-3 
                md:mt-8 
                w-[90%] 
                md:w-[80%] 
                lg:w-[50%] 
                drop-shadow-xl
                ">
                    {data?.description}
                </p>
                {!isLoading ?
                    <div className="flex flex-row items-center mt-3 md:mt-4 gap-3">
                        <button className="
                        bg-white 
                        text-white 
                        bg-opacity-30 
                        rounded-md 
                        py-1 md:py-2 
                        px-2 md:px-4 
                        w-auto 
                        text-xs lg:text-lg 
                        font-semibold 
                        flex flex-row 
                        items-center 
                        hover:bg-opacity-20
                        transition
                        ">
                            <AiOutlineInfoCircle className="mr-1" />
                            More Info
                        </button>
                    </div> : <></>
                }
            </div>
        </div>
    )
};

export default Billboard;

 

 

이렇게 코드를 작성하고 나면 아직은 상단부만 완성되었지만 제법 넷플릭스 같은 화면을 구경할 수 있다!!

728x90