Front-End/React

API를 호출할 때 useState 대신 useSWR을 사용해야 하는 이유

Voyage_dev 2023. 1. 9. 00:03

원문 :
https://javascript.plainenglish.io/why-you-should-use-useswr-instead-of-usestate-when-calling-apis-8b6de5dc18fc
https://velog.io/@ysg81/React-useSwr-사용하기
https://github.com/vercel/swr
https://swr.vercel.app/ko/docs/revalidation

SWR이란 무엇인가?

SWR(State While Revalidate)은 서버에서 데이터를 가져오는 데 사용되는 React 후크이다. useState와 useEffect를 사용하지 않고 실시간 데이터를 fetch, 캐싱 또는 re-fetch 할 수 있다. SWR은 캐시에서 데이터를 제공한 다음 검증을 위해 서버를 만들고 일단 완료되면 데이터 일관성을 위해 데이터를 결합한다.

 

NPM 혹은 YARN 설치 명령을 사용하여 SWR을 설치할 수 있다.

npm i swr

yarn add swr

어떻게 사용 하는가?

SWR은 간단한 React 후크이며 개체 모델의 오류뿐만 아니라 데이터를 반환한다.

import useSWR from 'swr'

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

  if (error) return <div>failed to load</div>
  if (!data) return <div>loading...</div>
  return <div>hello {data.name}!</div>
}

// or 

export const useXXX = () => {
  const { data, isValidating, error } = useSWR<ReturnDataType>(
    'key', async () => {
      // 비동기 통신 부분
      const res = await ...
      return res.data
    },
  );

  return {
    data,
    isLoading: isValidating,
    error,
  };
};
const { data, isValidating, error }
  • data는 비동기 통신으로 받아온 데이터이다. 타입스크립트에서 useState 타입을 지정해 주는 것 처럼 간단하게 선언해 줄 수 있다.
  • isValidating은 react-query에서 isFetching | isLoading 처럼 fetching 중인지를 알 수 있는 boolean 값이다.
const isLoading = (!data && !error) || isValidating
  • 완벽하게 예외를 제거하기 위해서는 위에처럼 error와 data를 모두 고려해서 주면 좋다.

매개변수가 존재할 때는 어떻게 해야 할까?

export const useXXX = (param: string) => {
  const { data, isValidating, error } = useSWR<ReturnDataType>(
    [param], async () => { // 필요한 param을 넣어주면 된다 이 값이 key 값이 된다.
      // 비동기 통신 부분
      const res = await axios.get('/api', { param })...
      return res.data
    },
  );

  return {
    data,
    isLoading: isValidating,
    error,
  };
};
const { data, isLoading, error } = useXXX(param); // hooks처럼 param 값만 넣어주면 된다

Axios를 밖으로 빼서 리팩토링 할 수도 있다.

const fetcher = async() => {
  const res = await axios.get(...)
  return res.data
}

export const useXXX = () => {
  const { data, isValidating, error } = useSWR<ReturnDataType>(
    'key', fetcher
  )
  return {
    data,
    isLoading: isValidating,
    error,
  };
};

// 매개변수가 있을 경우
const fetcher = async(param1: string) => {
  const res = await axios.get(...)
  return res.data
}

export const useXXX = () => {
  const { data, isValidating, error } = useSWR<ReturnDataType>(
    [param1], 
    fetcher
  )
  return {
    data,
    isLoading: isValidating,
    error,
  };
};
  • 보통 param 부분에 url을 많이 넣어주기 때문에 이 url이 key값이 된다.
  • 취향차이로 fetcher를 api로 useXXX를 hooks 폴더로 관리하면 유지보수면에서도 편리하겠다.

SWR에서 제공하는 기능

SWR은 더 나은 사용자 경험으로 애플리케이션을 구축할 수 있도록 성능, 정확성 및 안정성을 위한 다양한 기능을 제공한다.

성능

SWR은 고성능을 염두에 두고 Next.JS 팀에 의해 구축되었다. 불필요한 네트워크를 건너뛰는 캐싱 시스템과 중복 제거 시스템을 구축했다. React 후크이기 때문에 네트워크 호출로 인한 불필요한 재 렌더링을 피할 수 있다.

 

따라서 이점은 다음과 같다.

  • 불필요한 요청 없음
  • 불필요한 재렌더링 없음
  • 불필요한 코드를 가져오지 않음

Prefetching Data

기본적으로 <link ref="preload" href="..."/>를 추가하여 데이터를 미리 가져올 수 있다. 그러나 일부에서는 데이터를 프로그래밍 방식으로 미리 가져와야 한다.

 

SWR은 이러한 프로그래밍 방식으로 데이터를 미리 가져오는 옵션을 제공한다.

에러 핸들링

오류 처리는 모든 응용 프로그램에서 더 나은 사용자 경험을 제공하는 데 중요하다. SWR 는 전역적으로 오류를 처리하는 옵션을 제공하여 최종 빌드에서 많은 코드를 줄일 수 있다.

import React from "react";
import { SWRConfig } from "swr";

const App = () => {
  return (
    <SWRConfig
      value={{
        onError: (error, key) => {
          if (error.status !== 403 && error.status !== 404) {
            // We can send the error to Sentry,
            // or show a notification UI.
          }
        }
      }}
    >
      <MyApp />
    </SWRConfig>
	)
}

SWR을(를) 사용해 보자. 여러 가지 방법으로 응용 프로그램 성능이 향상된다.

revalidateOnFocus

브라우저 창을 다른 곳으로 focus를 옮기고 돌아오면 데이터가 재 랜더링이 되는 걸 방지하고 싶으면 revalidateOnFocus 옵션으로 막을 수 있다.

export const useXXX = () => {
  const { data, isValidating, error } = useSWR<ReturnDataType>(
    [param1], 
    fetcher,
  	// 포커싱 옵션
  	{ revalidateOnFocus: false },
  )
  return {
    data,
    isLoading: isValidating,
    error,
  };
};

조건부 랜더링

어떠한 변수값에 따라 swr을 실행시키고 싶으면

export const useXXX = (isTrigger: boolean) => {
  const { data, isValidating, error } = useSWR<ReturnDataType>(
    [param1], 
    // 조건부 랜더링
    isTrigger ? fetcher : null,
  )
  return {
    data,
    isLoading: isValidating,
    error,
  };
};

isTrigger가 true일 때만 즉, 원하는 시점에 실행시킬 수도 있다.

마무리

React 애플리케이션에서 우리는 일반적으로 데이터를 가져오고 콘텐츠를 렌더링하는데 useState 와 fetch를 사용 한다. useSWR를 사용하면 캐시에서 데이터를 제공하여 성능을 향상시킨 다음 확인을 위해 호출을 전송하고 마지막으로 데이터 일관성을 위해 두 데이터 소스를 결합한다.

 

다음에는 React-Query와 비교해 보는 공부를 해 봐야겠다.