Next.js 에서 SWR 좀 더 우아하게 사용하기 - (2 / 3)

신대현·2022년 9월 21일
4

SWR

목록 보기
2/3
post-thumbnail

Fetcher 옵션이 왜 필요해?

공식 문서에서는 이렇게 설명 하고 있습니다.

Fetcher은 SWR의 아주 핵심적인 API입니다. 여기의 fetcher는 SWR의 key를 받고 데이터를 반환하는 비동기 함수입니다.

// fetcher.ts
import axios from 'axios'

export const fetcher = (url:string, token:string = "", params = {}) => {
  if (typeof token === "object") {
    return axios.get(url, { params }).then((res) => res.data.data);
  }
  return axios
    .get(url, { params, headers: token ? { authorization: `Bearer ${token}` } : {} })
    .then((res) => res.data.data);
};
  • 저는 인증 권한을 받을수 있는 fetcher 로 커스텀 하여 사용했습니다.

Basic Using

function Article() {
  const { data } = useSWR('/api/article')
  return <h1>{data.title}</h1>
}
  • 기본으로 사용할 때의 코드입니다
  • 이전 포스팅에서 전역 설정으로 fetcher를 넣어주었기 때문에 위에처럼 fetcher를 생략 가능합니다

Custom Using

function Article() {
  const { data } = useSWR(['/api/userInfo',Token])
  return <h1>{data.userName}</h1>
}

or 

function Article() {
  const { data } = useSWR(['/api/userInfo',{ page:1 } ])
  return <h1>{data.userName}</h1>
}

or

function Article() {
  const { data } = useSWR(['/api/userInfo',Token,{ page:1 } ])
  return <h1>{data.userName}</h1>
}
  • 다중 인자 전달 참고
  • fetcher를 어떻게 커스텀을 하느냐에 따라 위와 같이 다양하게 활용이 가능합니다.

Fallback 옵션이 왜 필요해?

이전 포스팅에서 전역 설정에 fallback 옵션을 넣어주었습니다 넣어준 이유에 대해 알아보도록 하겠습니다

🙅 before

// page.tsx
const Page: NextPage = ({ newsData }) => {
const { data } = useSWR('/api/news', fetcher, { fallbackData: newsData })
 ....
};

export const getServerSideProps: GetServerSideProps = async () => {
  const newsData = await fetcher(`/api/news`);
  return {
    props: {
    	newsData
      },
    },
  };
};
  • 위의 코드는 전역 설정에 fallback 옵션을 사용하지 않았을때의 코드 입니다.
  • page의 뎁스가 깊어질수록 newsData를 props로 내려주게 되면서 비효율적인 코드가 될것입니다.

👍 SWR은 전역 캐시를 사용해 모든 컴포넌트 사이에 데이터를 저장하고 공유합니다 그렇기 때문에 아래와 같은 코드로 작성이 가능합니다.

🙆 after
// page.tsx
const Page = () =>{
 	return (
      <div>
        <NewsItem/>
        <PostItem/>
      </div> 
    )
}

export const getServerSideProps: GetServerSideProps = async () => {
  const [newsData, postData] = await Promise.all([
	 fetcher(`/api/news`),
	 fetcher(`/api/post`),
  ])
  return {
    props: {
    	fallback:{
    		['/api/news']:newsData,
            ['/api/post']:postData
      	}
    },
  };
};
<// NewsItem.tsx
const NewsItem = () =>{
  const { data:newsData } = useSWR('/api/news')
 	return <>{newsData.title}</> 
}
// PostItem.tsx
const NewsItem = () =>{
  const { data:postData } = useSWR('/api/post')
 	return <>{postData.title}</> 
}
  • 전역 설정으로 fallback을 사용할떄 주의사항은 캐시 적중을 시키기 위해선 fallback 으로 넘겨주는 key값과 useSWR key 값이 동일해야 pre-render가 가능합니다.

위의 데이터는 캐시된 데이터이고
useSWRConfig hook을 사용해 전역 설정과 mutate 및 cache 를 얻을 수 있습니다.

중복 제거

SWR 성능

SWR을 사용하면서 정말 편하다고 생각한 부분입니다
이전에 설명 한데로 SWR은 전역 캐시를 사용해 모든 컴포넌트 사이에 데이터를 저장하고 공유합니다
아래의 코드를 봤을때 당연히 Avatar 컴포넌트가 5개가 렌더링 되고 네트워크 요청이 5번을 할꺼 같지만 SWR 에서는 동일한 SWR Key를 갖고 있으므로 거의 동시에 렌더링 되며
단 한 번의 네트워크 요청만 발생합니다.


function Avatar () {
  const { data, error } =  useSWR('/api/user', fetcher)

  if (error) return <Error />
  if (!data) return <Spinner />

  return <img src={data.avatar_url} />
}

function App () {
  return <>
    <Avatar />
    <Avatar />
    <Avatar />
    <Avatar />
    <Avatar />
  </>
}

다음 포스팅에서는 typescript,인증, custom hooks, 인피니티 로딩을 다루어 보도록 하겠습니다.

참고

https://swr.vercel.app/ko

profile
프론트엔드 개발자 입니다

0개의 댓글