Front-End/Next

useSWR로 API 호출 재사용성 높이기

Voyage_dev 2023. 3. 13. 01:34

SWR란?

React-Query와 비슷한 개념으로 서버에서 데이터를 가져와서 사용하는 Vercel이 개발한 React hooks이다.
더 자세한 개념이랑 사용 방법은 전 글을 참고하자

이번에는 SWR hooks로 데이터를 프리렌더링 하며 axios를 이용해 호출 재사용성 높이는 방법을 알아보자.

 

useSWR 함수

SWR 함수는 기본적으로 1개의 인자를 필수로 받는다.

  • key : fetcher 함수에게 전달되는 인자 ⇒ 보통 URL을 넣는다
  • fetcher : 데이터를 실질적으로 fetch하는 함수이다
  • option : revalidate , mutate, initialData 등 옵션을 넣어줄 수 있다

사용 순서는 다음과 같다.

  • fetcher를 만든다. 여기서 불러오는 데이터의 url을 지정하고 불러오게 된다.
import axios from "axios";

export const fetcher = (url: string) => axios.get(url);
  • 데이터를 요청할 때 사용할 key값을 fetcher와 함께 넘겨준다.
const { data, error, isValidating, mutate } = useSWR(key, fetcher, options)

재사용성 높이기

import type { AppProps } from "next/app";
import { ThemeProvider } from "styled-components";
import GlobalStyles from "@styles/_GlobalStyles";
import { color, mixins } from "@styles/_theme";
import Layout from "@components/Common/Layout";
import { SWRConfig } from "swr";
import { request } from "lib/axios-utils";
import Head from "next/head";
import "@fortawesome/fontawesome-svg-core/styles.css";

export default function App({ Component, pageProps }: AppProps) {
  return (
      <ThemeProvider theme={{ ...color, ...mixins }}>
        <GlobalStyles />
        <SWRConfig value={{ fetcher: request }}>
          <Layout>
            <Component {...pageProps} />
          </Layout>
        </SWRConfig>
      </ThemeProvider>

  );
}

app.tsx에서 SWRConfig로 fetcher를 감싸주므로 SWR을 전역적으로 사용하는 모든 곳에서 fetcher 함수를 넣어주지 않아도 된다.

const SellerPage = ({ seller, qna }: Props) => {

  const { data: sellerData, error } = useSWR(`?q=sellers`, {
    fallbackData: seller,
  });
})

이런식으로 useSWR에 key 값만 넣어놔도 알아서 fetcher 함수가 실행된다. 여기서 fallbackData는 미리 pre-rendering 된 데이터를 넣어주므로 인해 아직 데이터가 도착하지 않았을 때 보여줄 내용을 미리 넣어두는 것이라고 할 수 있다.

 

아까 SWRConfig fetcher에 request 함수를 설정했다.

// request
import axios from "axios";

const client = axios.create({
  baseURL: "/api",
});

export const request = async ({ ...options }) => {
  const queryParam = Object.values(options).join("");

  client.defaults.headers.common.Authorization = "Bearer token";
  const onSuccess = (response: any) => response;
  const onError = (error: Error) => {
    return error;
  };

  return client(queryParam).then(onSuccess).catch(onError);
};

여기서 queryParam으로 한 번 처리한 이유는 key값이 split된 형태인 “?”, “q”, ”=” ”s”, ”e”, ”l”, ”l”, ”e”, ”r”, ”s” 로 들어오기 때문에 한 번 처리해서 원하는 api 위치로 보내기 위함이다.

또 이렇게 q= 형태로 보내면 next는 req.query.q로 값을 받을 수 있기 때문에 기본적인 base url이 같고 api 뒤 값만 다르다면 api 폴더를 하나로 관리할 수 있다.

import axios from "axios";
import { BASE_URL } from "config";
import type { NextApiRequest, NextApiResponse } from "next";

const client = axios.create({
  baseURL: BASE_URL,
  headers: {
    Accept: "application/json",
  },
  withCredentials: true,
});

const getData = async (req: NextApiRequest, res: NextApiResponse) => {
  const query = req.query.q; // 이 부분!

  const { data } = await client.get(`/api/${query}?populate=*`);

  return res.status(200).json(data.data);
};

export default getData;

요청하는 api값이 다르다면 요청하는 폴더를 만들어야 되지만, 뒤에 값만 다르다면 이렇게 하나로 관리할 수 있기 때문에 불필요한 파일을 작성할 필요가 없다.

 

참고로 pre-rendering 시에는 요청 보낼 주소를 다 적어야 한다. 그 이유는 prefetch되는 서버에서는 기본적으로 모든 URL이 있어야 해당 데이터를 요청 및 받을 수가 있다.

import SellerPage from "@components/Pages/Seller";
import { Props } from "@components/Pages/Seller/types";
import { BASE_URL } from "config";
import { fetcher } from "lib/fetcher";
import { GetStaticProps } from "next";
import React from "react";

const Seller = ({ seller }: Props) => {
  return <SellerPage seller={seller} />;
};

export default Seller;

// pre-rendering
// 서버에서 데이터 요청 받은 후 빌드시에 클라이언트로 보내주는 코드이다
export const getStaticProps: GetStaticProps = async () => {
  const seller = await fetcher(`${BASE_URL}/api/sellers`).then(
    data => data.data
  );

  return {
    props: {
      seller,
    },
  };
};

 

출처 : 아래의 사이트들을 보면서 큰 공부 하였습니다