[Culture Place제작기-3-] Nextjs와 함께하는 React Query -1-

column clash·2021년 9월 28일
0
post-custom-banner

마인드케어 제작당시에는 swr 로 데이터패치를 했지만,
아쉬운 점이 get 요청으로만 제작되었다는 점이다.

물론, axios 에서 post 요청이나 delete put 요청등을
주고 난후에, mutate 의 활용으로
충분히 유용하게 사용할 수 있기에, swr 도 매우
좋은 툴이라 생각하지만,

npm trends 에서 React Query 의 사용도가 압도적이라는
점과 get 이외의 요청에도 mutation 에서 기능을
제공한다는 점에서 흥미를 느껴 이번 프로젝트에
도입해보기로 하였다. ( + 더 많은 라이브러리들을 다뤄볼 생각으로)

한국어로 된 자료가 부족한 점이 아쉽지만,
기록해둔다. (크롬의 번역기능만으로도 충분히 익힐 수 있다.)

공식홈페이지
https://react-query.tanstack.com

_app.js

import React from "react";
import "../styles/globals.css";
import type { AppProps } from "next/app";
import { Hydrate, QueryClient, QueryClientProvider } from "react-query";
import { ReactQueryDevtools } from "react-query/devtools";

export default function MyApp({ Component, pageProps }: AppProps) {
  const [queryClient] = React.useState(() => new QueryClient());

  return (
    <QueryClientProvider client={queryClient}>
      <Hydrate state={pageProps.dehydratedState}>
        <Component {...pageProps} />
      </Hydrate>
      <ReactQueryDevtools />
    </QueryClientProvider>
  );
}

_app.js 는 공식홈페이지에서 copy + paste 했다.
context provider 처럼 provider 로 감싸고,
hybrate 로 감싸고 있다.

지난 2회차에서 다루었던 것을 리액트 쿼리로 재구성해보았다.

hooks/api
usePosts.tsx

import axios from "axios";
import { useQuery } from "react-query";

const fetchPosts = async (limit = 10) => {
  const { data } = await axios("https://jsonplaceholder.typicode.com/posts");
  const result = data.filter((x: any) => x.id <= limit);
  return result;
};

const usePosts = (limit: number) => {
  return useQuery(["posts", limit], () => fetchPosts(limit));
};

export { usePosts, fetchPosts };

pages/index

import Link from "next/link";
import React from "react";
import { dehydrate, QueryClient, useQuery } from "react-query";
import { fetchPosts } from "../hooks/apis/usePosts";

const Home = () => {
  const { isLoading, error, data } = useQuery<any[], Error>("posts", () =>
    fetchPosts(10)
  );

  if (isLoading) return <div>Loading</div>;
  if (error) return "An error has occurred: " + error?.message;

  return (
    <>
      <div>index</div>
      <Link href="/test">
        <a>test페이지로</a>
      </Link>
      <ul>
        {data?.map((post: any) => (
          <li key={post.id}>
            <div>
              <span>{post.id}. </span>
              <span key={post.id}>
                <Link href={`/ssr2/${post.id}`}>{post.title}</Link>
              </span>
              <a href="#">{post.title}</a>
            </div>
          </li>
        ))}
      </ul>
    </>
  );
};

export async function getStaticProps() {
  const queryClient = new QueryClient();

  await queryClient.prefetchQuery("posts", () => fetchPosts(10));

  return {
    props: {
      dehydratedState: dehydrate(queryClient),
    },
  };
}

export default Home;

ssr2/[id].tsx

import React from "react";
import { useRouter } from "next/router";
import { dehydrate, QueryClient, useQuery } from "react-query";
import { fetchPosts } from "../../hooks/apis/usePosts";
import Link from "next/link";

interface Post {
  title: string;
  body: string;
  id: number;
}

function Ssr2() {
  const { isLoading, error, data } = useQuery<Post[], Error>("posts", () =>
    fetchPosts(10)
  );
  const router = useRouter();
  const { id } = router.query;
  const idx = Number(id) - 1;

  if (isLoading) return <div>Loading</div>;
  if (error) return "An error has occurred: " + error?.message;
  return (
    <div className="Detail">
      <Link href="/">
        <a>index로</a>
      </Link>
      {data && (
        <>
          <h1>{data[idx].title}</h1>
          <p>{data[idx].body}</p>
          <p>{data[idx].id}번째 게시글</p>
        </>
      )}
    </div>
  );
}

export async function getServerSideProps() {
  const queryClient = new QueryClient();

  await queryClient.prefetchQuery("posts", () => fetchPosts(10));

  return {
    props: {
      dehydratedState: dehydrate(queryClient),
    },
  };
}

export default Ssr2;

데이터 캐시 및 패치,
getStaticProps (ssg) 와
getServerSideProps (ssr) 이 잘 동작되는 것을 확인할 수 있었다.
(테스트 중이라, type 을 any 라고 적었으나 실제 작업 중에는 제대로
된 type 을 적어줘야 타입스크립트를 쓰는 이유가 있으니, 실제 본 작업에
들어가서는 any 를 타입으로 바꿔주자)

다음편에서는 mutation 에 대해서 알아보자

profile
풀스택 개발 중...
post-custom-banner

0개의 댓글