유데미, React Query: Server State Management in React 강의를 바탕으로 작성한 글입니다.
React Query를 공부하면서 챕터별로 배운내용을 정리하려고 합니다.
React Query를 목적/기능별로 어떻게 사용해야하는지 코드로 구분해 설명합니다.
css는 styled-components를 사용했습니다.
'아래문장을 클릭해보세요' 문구 아래,
내용을 클릭하면, react-query가 클릭한 내용에 해당하는 아이템을 fetching 해오고 있습니다.
- Components : 컴포넌트 파일을 담는 폴더 입니다
- basic: react-query의 기본 기능(fetching)을 구현한 파일들을 담고 있습니다.
- pagination:react-query로 pagination을 구현한 파일들을 담고 있습니다.[다음장에서 다루겠습니다.]
- Server: Fetcher 파일에는 api 주소를 모두 저장하고 있는 파일입니다.
- Views/Asssets/Style: global 스타일을 설정하는 곳입니다.
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에 내장되어 있는 기본 프로퍼티이다.
구조분해{}를 통해 값을 가져온다
if (!data) return <div />;
...중략...
<ul className="click-item">
{data.map((post) => (
<li key={post.id} onClick={() => setSelectedPost(post)}>
{post.title}
</li>
))}
</ul>
data가 undefined 될 경우, 위와 같이 처리한다.
import React from "react";
function ItemDetail({ post }) {
return (
<>
<h4 className="title">Title: {post.title}</h4>
<p>{post.body}</p>
</>
);
}
export default ItemDetail;
const BaseUrl = `https://jsonplaceholder.typicode.com/posts?_limit=10&_page=0`;
export const fetchPost = async () => {
const response = await (await fetch(BaseUrl)).json();
return response;
};
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
페이지 전체의 스타일을 정의합니다.
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는 데브툴즈다
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;
}
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")
);