[#기본] React-Query로 데이터 fetching 하기

유데미, React Query: Server State Management in React 강의를 바탕으로 작성한 글입니다.

React Query를 공부하면서 챕터별로 배운내용을 정리하려고 합니다.
React Query를 목적/기능별로 어떻게 사용해야하는지 코드로 구분해 설명합니다.
css는 styled-components를 사용했습니다.

작업한 코드는 "여기" 브랜치, features/react-query에서 확인 가능합니다.

아래화면은 코드를 모두 작성하면 확인 가능한 화면입니다.

화면설명

'아래문장을 클릭해보세요' 문구 아래,
내용을 클릭하면, react-query가 클릭한 내용에 해당하는 아이템을 fetching 해오고 있습니다.

폴더구조

- Components : 컴포넌트 파일을 담는 폴더 입니다
- basic: react-query의 기본 기능(fetching)을 구현한 파일들을 담고 있습니다.
- pagination:react-query로 pagination을 구현한 파일들을 담고 있습니다.[다음장에서 다루겠습니다.]
- Server: Fetcher 파일에는 api 주소를 모두 저장하고 있는 파일입니다.
- Views/Asssets/Style: global 스타일을 설정하는 곳입니다.

Item.jsx

import React, { useState } from "react";
import { useQuery } from "react-query";
import { fetchPost } from "../../Server/Fetcher.js";
import ItemDetail from "./ItemDetail";

function Item() {
  const [selectedPost, setSelectedPost] = useState(null);
  const { isLoading, isError, error, data } = useQuery("posts", fetchPost);
  if (!data) return <div />;
  if (isLoading) return <h1>로딩중입니다..</h1>;

  return (
    <>
      {!isError ? (
        <div className="content">
          <strong>아래 문장을 클릭해보세요</strong>
          <ul className="click-item">
            {data.map((post) => (
              <li key={post.id} onClick={() => setSelectedPost(post)}>
                {post.title}
              </li>
            ))}
          </ul>
          {selectedPost && <ItemDetail post={selectedPost} />}
        </div>
      ) : (
        <div>
          <h2>에러가 발생했습니다!</h2>
          <p>{error}</p>
        </div>
      )}
    </>
  );
}

export default Item;

코드설명

const { isLoading, isError, error, data } = useQuery("posts", fetchPost,;

isLoading, isError, error, data는 useQuery에 내장되어 있는 기본 프로퍼티이다.

구조분해{}를 통해 값을 가져온다

  • isLoading: true/fase 값을 가지며, Loading일때, 아닐때 경우를 갖고 싶을 때 사용할 수 있다.
  • isError : true/fase 값을 가지며 isLoading과 내용은 같다.
  • error : 구체적으로 어떤 에러인지를 알려준다.
  • (중요) data : api에서 가져온 데이터가 담긴다
  • (중요) posts : ""안에 들어간 값은 useQuery가 api를 가져올 때 , 어떤 키로 가져올 것인가를 의미한다. ""안에 들어간 텍스트는 유니크해야한다. posts라고 하지 않아도 된다. 자유롭게 작성해도 된다.여러 post를 가지고 온다고 posts라고 한 것이다.
  • (중요) fetchPost : api를 fetching 하는 함수다, 위 코드에서 fetcher.js에 들어있다. 함수명을 적어준다.
if (!data) return <div />;

...중략...

<ul className="click-item">
  {data.map((post) => (
     <li key={post.id} onClick={() => setSelectedPost(post)}>
      {post.title}
     </li>
   ))}
</ul>

data가 undefined 될 경우, 위와 같이 처리한다.

ItemDetail.jsx

import React from "react";

function ItemDetail({ post }) {
  return (
    <>
      <h4 className="title">Title: {post.title}</h4>
      <p>{post.body}</p>
    </>
  );
}

export default ItemDetail;

Fetcher.js

const BaseUrl = `https://jsonplaceholder.typicode.com/posts?_limit=10&_page=0`;

export const fetchPost = async () => {
  const response = await (await fetch(BaseUrl)).json();
  return response;
};

GlobalStyle.js

import {createGlobalStyle} from 'styled-components';

const GlobalStyle = createGlobalStyle`
    html, body,  *{
        margin:0; padding:0; box-sizing:border-box;
    }
    a{ text-decoration:none;}
    ul, li{ list-style:none;}
    fieldset { border: 1px solid #c0c0c0; margin: 0 2px; padding: 0.35em 0.625em 0.75em; }
    legend { border: 0;  padding: 0;  }
    textarea { overflow: auto; }
    optgroup { font-weight: bold; }
    table { border-collapse: collapse; border-spacing: 0; }
    td, th { padding: 0; }
    main,nav,footer{display:block; width:100%;}
`
export default GlobalStyle

페이지 전체의 스타일을 정의합니다.

App.js

import Items from "./Components/basic/Items";
import { ReactQueryDevtools } from "react-query/devtools";
import { QueryClient, QueryClientProvider } from "react-query";
const queryClient = new QueryClient();

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <div className="App">
        <h1 className="title">Blog Posts</h1>
        <Items />
      </div>
      <ReactQueryDevtools />
    </QueryClientProvider>
  );
}

export default App;
import { ReactQueryDevtools } from "react-query/devtools";
import { QueryClient, QueryClientProvider } from "react-query";
const queryClient = new QueryClient();

...중략...

<QueryClientProvider client={queryClient}>
...중략...
  <ReactQueryDevtools />
</QueryClientProvider>

useQuery를 쓰기위한 기본 세팅이다.
ReactQueryDevtools는 데브툴즈다

index.css

  • 스타일은 react-query와 별개의 것이라 참고만 하면 된다.
body {
  margin: 0;
  font-family: sans-serif;
  background: #222;
  color: #ddd;
  text-align: center;
}
.App {
  width: 960px;
  margin: 0 auto;
}
.content {
  text-align: left;
}
li {
  cursor: pointer;
  display: flex;
}
h1,
h2,
h3,
h4 {
  color: #ffff57;
  font-size: 4em;
  letter-spacing: 2px;
}
.title {
  text-align: left;
  margin-bottom: 10px;
  border-bottom: 1px solid;
}
button {
  margin: 0 10px;
  background: transparent;
  border: 3px solid #ccc;
  border-radius: 20px;
  padding: 10px;
  color: #ccc;
  font-size: 1.2em;
  cursor: pointer;
}
button:hover {
  color: #fff;
  border-color: #fff;
}

.post-title {
  color: pink;
  font-size: 30px;
  margin: 10px 0;
}
.pages-buttons {
  display: flex;
  justify-content: space-between;
  margin: 20px 0 20px 0;
}

.middle {
  display: inline-block;
  vertical-align: top;
  margin-top: 20px;
}

.click-item {
  margin-bottom: 20px;
}

.li-title,
.li-content {
  display: inline-block;
  vertical-align: top;
}

.li-title {
  margin-right: 10px;
}

index.js

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import "./index.css";
import GlobalStyle from "./Views/Assets/Style/GlobalStyle";

ReactDOM.render(
  <React.StrictMode>
    <GlobalStyle />
    <App />
  </React.StrictMode>,
  document.getElementById("root")
);

좋은 웹페이지 즐겨찾기