ํ์ฌ ํ์ด์ง(current Page) ์ํ๋ฅผ ํตํด, ํ์ฌ ํ์ด์ง๋ฅผ ํ์ ํ๋ ํ์ด์ง ๋งค๊น ๋ฐฉ๋ฒ
- ๋๊ธ์์ ์์ ํ๋ ๊ฒ์ฒ๋ผ ํ์ด์ง๋ง๋ค ๋ค๋ฅธ ์ฟผ๋ฆฌ ํค ๊ฐ ํ์ ํฉ๋๋ค.
- ๋ฐ๋ผ์, ์ฟผ๋ฆฌ ํค๋ฅผ ๋ฐฐ์ด ๋ก ์ ๋ฐ์ดํธํด์ ๊ฐ์ ธ์ค๋ ํ์ด์ง ๋ฒํธ๋ฅผ ํฌํจ ํ๋๋ก ํ๊ฒ ์ต๋๋ค.
- ์ฌ์ฉ์๊ฐ ๋ค์, ๋๋ ์ด์ ํ์ด์ง๋ก ๊ฐ๋ ๋ฒํผ์ ๋๋ฅด๋ฉด currentPage ์ํ๋ฅผ ์ ๋ฐ์ดํธ ํฉ๋๋ค.
- ๊ทธ๋ผ React Query ๊ฐ ๋ฐ๋ ์ฟผ๋ฆฌ ํค๋ฅผ ๊ฐ์งํ๊ณ ์๋ก์ด ์ฟผ๋ฆฌ๋ฅผ ์คํํด์ ์ ํ์ด์ง๊ฐ ํ์๋ฉ๋๋ค.
โ Posts.js
import React, { useState } from "react";
import { useQuery } from "react-query";
import { PostDetail } from "./PostDetail";
const maxPostPage = 10;
async function fetchPosts() {
const response = await fetch(
"https://jsonplaceholder.typicode.com/posts?_limit=10&_page=0"
);
return response.json();
}
export function Posts() {
const [currentPage, setCurrentPage] = useState(1);
const [selectedPost, setSelectedPost] = useState(null);
// replace with useQuery
const {data, isLoading, isError, error} = useQuery('posts', fetchPosts, {staleTime : 2000});
// ๋ง์ฝ ๋ก๋ฉ ์ค์ด๋ผ๋ฉด
if(isLoading){
return <h3>Loading...</h3>;
}
if(isError){
return (
<React.Fragment>
<h3>Sorry, no Data</h3>
<p>{error.toString()}</p>
</React.Fragment>
)
}
return (
<>
<ul>
{data.map((post) => (
<li
key={post.id}
className="post-title"
onClick={() => setSelectedPost(post)}
>
{post.title}
</li>
))}
</ul>
<div className="pages">
<button disabled onClick={() => {}}>
Previous page
</button>
<span>Page {currentPage + 1}</span>
<button disabled onClick={() => {}}>
Next page
</button>
</div>
<hr />
{selectedPost && <PostDetail post={selectedPost} />}
</>
);
}
โ ์ฟผ๋ฆฌ ํค ์ถ๊ฐ
const [currentPage, setCurrentPage] = useState(1);
// ์ฟผ๋ฆฌ ํค์ currentPage ๋ฅผ ํฌํจํฉ๋๋ค.
const {data, isLoading, isError, error} = useQuery(['posts', currentPage] fetchPosts, {staleTime : 2000});
- ์์ ๊ฐ์ด ์ฟผ๋ฆฌ ํค์ currentPage ๋ฅผ ํฌํจํ๊ฒ ๋๋ฉด React Query ๊ฐ ๋ฐ๋ ์ฟผ๋ฆฌ ํค๋ฅผ ๊ฐ์งํด์ ์ ์ฟผ๋ฆฌ ํค์ ๋ํ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฐ์ดํธ ํฉ๋๋ค.
โ ์ฟผ๋ฆฌ ํจ์๋ ์ ๋ฐ์ดํธ
async function fetchPosts() {
const response = await fetch(
"https://jsonplaceholder.typicode.com/posts?_limit=10&_page=0"
);
return response.json();
}
- ํ์ฌ ์ฟผ๋ฆฌ ํจ์๋ ํ์ด์ง 0 ์ ๊ฐ์ ธ์ค๋๋ก ํ๋ ์ฝ๋ฉ๋์ด ์์ด์ currentPage ์ state๊ฐ 1 ,
- ์ฆ, ํ์ด์ง๊ฐ 1๋ถํฐ ์์ํด๋ page=0 ์ ์คํํ๋ฉด ํ์ด์ง 0์ด ๋์ฌ ๊ฒ ์ ๋๋ค.
- ์ด๋ค ํ์ด์ง ๋ฒํธ๋ฅผ ์ ๋ ฅํ๋ ๊ฐ์ ๊ฐ์ ธ์ฌ ์ ์๋๋ก ๋ง๋ค๋ ค๋ฉด ์ฟผ๋ฆฌ ํจ์์ pageNum ๋ฅผ ์ธ์๋ก ๋ฐ๊ณ
- page=0 ์, ์ธ์๋ก ์ฌ์ฉ๋๋ ์ด๋ค ํ์ด์ง ๋ฒํธ๋ ๊ฐ์ ธ์ฌ ์ ์๋๋ก ์๋ ์ฒ๋ผ ๋ฐ๊ฟ๋๋ค.
async function fetchPosts(pageNum) {
const response = await fetch(
`https://jsonplaceholder.typicode.com/posts?_limit=10&_page=${pageNum}`
);
return response.json();
}
- ๋ํ ๊ฒ์๋ฌผ์ ๊ฐ์ ธ์ฌ ๋ฟ๋ง ์๋๋ผ ๋๊ธ์์ ํ๋ ๊ฒ ์ฒ๋ผ currentPage ๊ฐ ๋ฌด์์ด๋ ๊ฐ์ fetchPosts ํจ์๋ฅผ ์คํํด์ผ ํฉ๋๋ค.
const {data, isLoading, isError, error}= useQuery(['posts', currentPage],
() => fetchPosts(currentPage), {staleTime : 2000});
- ['posts', currentPage] ์ด ๋ฐฐ์ด์ด ๋ฐ๋๋ฉด ํจ์๋ ๋ฐ๋๊ธฐ ๋๋ฌธ์(fetchPosts) ๋ฐ์ดํฐ๊ฐ ๋ฐ๋ ์ ๋ฐ์ ์์ต๋๋ค.
- ๋ฐ๋ผ์ ์ฟผ๋ฆฌ ํค๊ฐ ๋ฐ๋๋ฉด useQuery์ ์๋ก์ด ์ฟผ๋ฆฌ๋ฅผ ์๋ ค์ ๋ฐ์ดํฐ๋ฅผ ๋ค์ ๊ฐ์ ธ์ค๋๋ก ๋ง๋ ๊ฒ ์ ๋๋ค.
๋ฒํผ ํ์ฑํ
โ ์ด์ ๋ฒํผ
๋ฒํผ์ ๊ธฐ๋ณธ์ ์ผ๋ก disabled ๋์ด ์๋๋ฐ ๋ง์ฝ, currentPage ๊ฐ 1๊ณผ ๊ฐ๊ฑฐ๋ 1๋ณด๋ค ์์ผ๋ฉด ์ด์ ๋ฒํผ์ ๋นํ์ฑํ ํด์ผ ํฉ๋๋ค.
<button disabled={currentPage <= 1}
onClick={() => {setCurrentPage((currentPage) => currentPage - 1 }}>
Previous page
</button>
- ์ฆ, ํ์ด์ง๊ฐ 1์ ์๊ฑฐ๋, ์ค์๋ก ํ์ด์ง 1์ ์ผ๋ก ๊ฐ๊ฒ ๋๋ฉด ์ด์ ๋ฒํผ์ ํ์ฑํํ์ง ์์์ผ ํฉ๋๋ค.
- onClick์๋ currentPage ๋ฅผ setCurrentPage์ currentPage - 1 ๊ฐ์ ๋ฐํํ๋ ํจ์๋ฅผ ์ค๋๋ค.
โ ๋ค์ ๋ฒํผ
์์ ์๋จ์ maxPostPage ๋ฅผ 10์ผ๋ก ์ค์ ํ์ต๋๋ค.
const maxPostPage = 10;
// ํ๊ณ๊ฐ 10 ์
๋๋ค.
"https://jsonplaceholder.typicode.com/posts?_limit=10&_page=${pageNum}"
- ๋ํ API ๊ฐ 100๊ฐ์ ๊ฒ์๋ฌผ์ ๋ฐํํ๋ค๊ณ ํด์ ์ต๋ ํ์ด์ง ์๋ฅผ 10์ผ๋ก ์ค์ ํ์ต๋๋ค.
const {data, isLoading, isError, error} = useQuery('posts', fetchPosts, {staleTime : 2000});
๋ง์ฝ data ๊ฐ ๋ค์ ํ์ด์ง ์ ๋ฌด์ ๋ํ ํ๋กํผํฐ๋ฅผ ๊ฐ์ง๊ณ ์๋ค๋ฉด, ๋ฒํผ์ ํ์ฑํํ ์ง ํ๋จํ๋ ์งํ๋ก ์ฌ์ฉ ํ ์ ์์ต๋๋ค.
๋ฒํผ์ด disabled ์ธ ๊ฒฝ์ฐ๋ currentPage ๊ฐ maxPostPage ์ ๊ฐ๊ฑฐ๋ ๊ทธ๋ณด๋ค ํด ๊ฒฝ์ฐ๊ฐ ๋ฉ๋๋ค.
<button disabled={currentPage >= maxPostPage}
onClick={() => {setCurrentPage((currentPage) => currentPage + 1 }}>
Next page
</button>
- onClick ์ ์ ๊ณผ ๋น์ทํ๋ฐ 1์ ๋นผ๋ ๋์ 1์ ๋ํฉ๋๋ค.
โ ์ ์ฒด ์ฝ๋
import React, { useState } from "react";
import { useQuery } from "react-query";
import { PostDetail } from "./PostDetail";
const maxPostPage = 10;
async function fetchPosts(pageNum) {
const response = await fetch(
`https://jsonplaceholder.typicode.com/posts?_limit=10&_page=${pageNum}`
);
return response.json();
}
export function Posts() {
const [currentPage, setCurrentPage] = useState(1);
const [selectedPost, setSelectedPost] = useState(null);
// replace with useQuery
const {data, isLoading, isError, error} = useQuery(['posts', currentPage], () => fetchPosts(currentPage), {staleTime : 2000});
// ๋ง์ฝ ๋ก๋ฉ ์ค์ด๋ผ๋ฉด
if(isLoading){
return <h3>Loading...</h3>;
}
if(isError){
return (
<React.Fragment>
<h3>Sorry, no Data</h3>
<p>{error.toString()}</p>
</React.Fragment>
)
}
return (
<>
<ul>
{data.map((post) => (
<li
key={post.id}
className="post-title"
onClick={() => setSelectedPost(post)}
>
{post.title}
</li>
))}
</ul>
<div className="pages">
<button disabled={currentPage <= 1}
onClick={() => {setCurrentPage((currentPage) => currentPage - 1);}}>
Previous page
</button>
<span>Page {currentPage}</span>
<button disabled={currentPage >= maxPostPage}
onClick={() => {setCurrentPage((currentPage) => currentPage + 1);}}>
Next page
</button>
</div>
<hr />
{selectedPost && <PostDetail post={selectedPost} />}
</>
);
}
โ ๊ฒฐ๊ณผ
- ํ์ด์ง ์ ํ์ด ์ ๋๋ ๋ณผ ์ ์์ต๋๋ค.
- ํ์ง๋ง ๋ค์ ํ์ด์ง๋ก ๋์ด๊ฐ๋ ๋์ค์ ๋ก๋ฉ์ด ๋์์ ์ฌ์ฉ์ ๊ฒฝํ์ ๋ฐฉํด๋ฅผ ์ค๋๋ค.
- ๋ค์ ํฌ์คํ ์์ ๋ค์ ํ์ด์ง ๊ฒฐ๊ณผ๋ฅผ ํ๋ฆฌํจ์นญ(Prefetching) ํด์ ๋ฐ๋ก ๋ณด์ผ ์ ์๋๋ก ํ๊ฒ ์ต๋๋ค.
โ ์ฐธ๊ณ
'๐ Front-End > React.js' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
React Query - isFetching VS. isLoading (0) | 2022.10.25 |
---|---|
React Query - ๋ฐ์ดํฐ ํ๋ฆฌํจ์นญ(Pre-fetching) (0) | 2022.10.25 |
React Query - ์ฟผ๋ฆฌ ํค (0) | 2022.10.25 |
React Query - staleTime vs cacheTime (0) | 2022.10.25 |
React Query - Dev Tools (0) | 2022.10.25 |