728x90
반응형
반응형
데이터 가져오기
페이지네이션을 하기 위해서는 데이터가 있어야 한다. 우선은 데이터가 없으므로 게시물 데이터는 JSON Placeholder라는 인터넷에 공개된 API를 통해 가져온다.
fetch('<https://jsonplaceholder.typicode.com/todos/1>')
.then(response => response.json())
.then(json => console.log(json))
이렇게 데이터를 가져온다.
사이트를 참고하면 이렇게 fetch를 사용해서 가져온 데이터는 아래와 같은 데이터로 가져와진다.
{
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": false
}
게시물 목록 구현
import { useState, useEffect } from "react";
import styled from "styled-components";
import Pagination from "./Pagination";
- 변수 선언을 위한 useState와 jsonPlaceholder에서 가져온 데이터를 배열을 만들어 담아줘야 함으로 useEffect를 임포트해왔다.
- 컴포넌트에 스타일을 적용해야 함으로 styled-components를 임포트해왔다.
- Pagination는 페이지 목록을 보여준다.
function Posts() {
const [posts, setPosts] = useState([]);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/posts")
.then((res) => res.json())
.then((data) => setPosts(data));
}, []);
return (
<Layout>
<header>
<h1>게시물 목록</h1>
</header>
<main>
{posts.map(({ id, title, body }) => (
<article key={id}>
<h3>
{id}. {title}
</h3>
<p>{body}</p>
</article>
))}
</main>
</Layout>
);
}
const Layout = styled.div`
display: flex;
flex-direction: column;
align-items: center;
max-width: 800px;
margin: 0 auto;
`;
export default Posts;
→ useEffect를 사용해 데이터를 가져와서, 배열에 json을 하나씩 넣어준다. 그리고 배열을 하나씩 게시물 목록으로 보여준다.
페이지네이션을 위한 변수
const [posts, setPosts] = useState([]);
const [limit, setLimit] = useState(10);
const [page, setPage] = useState(1);
const offset = (page - 1) * limit;
- posts : 배열 형식으로, json형식으로 가져온 데이터를 여기에 넣어준다.
- limit : 페이지마다 몇개의 데이터를 보여줄 것인지 알려주는 데이터이다.
- page : 사용자가 클릭한 페이지를 말한다.
- offset : 페이지의 첫 게시물의 위치를 말한다.
- 현재 페이지 번호를 기준으로 표시해줘야할 게시물의 범위를 알아야 한다. 해당 페이지의 첫 게시물의 위치(index)를 알아야 한다. 그래야 페이지당 limit로 설정한 값만큼의 게시물을 보여줄 수 있다.
페이지네이션 구현
import styled from "styled-components";
function Pagination({ total, limit, page, setPage }) {
const numPages = Math.ceil(total / limit);
return (
<>
<Nav>
<Button onClick={() => setPage(page - 1)} disabled={page === 1}>
<
</Button>
{Array(numPages)
.fill()
.map((_, i) => (
<Button key={i + 1}onClick={() => setPage(i + 1)}aria-current={page === i + 1 ? "page" : null}>
{i + 1}
</Button>))}
<Button onClick={() => setPage(page + 1)} disabled={page === numPages}>
>
</Button>
</Nav>
</>);
}
const Nav = styled.nav`
display: flex;
justify-content: center;
align-items: center;
gap: 4px;
margin: 16px;
`;
const Button = styled.button`
border: none;
border-radius: 8px;
padding: 8px;
margin: 0;
background: black;
color: white;
font-size: 1rem;
&:hover {
background: tomato;
cursor: pointer;
transform: translateY(-2px);
}
&[disabled] {
background: grey;
cursor: revert;
transform: revert;
}
&[aria-current] {
background: deeppink;
font-weight: bold;
cursor: revert;
transform: revert;
}
`;
export default Pagination;
여기서는 상위 컴포넌트로부터 총 게시물 수(total)와 페이지 당 게시물 수(limit) 그리고 현재 페이지 번호(page)를 prop으로 받는다.
728x90
반응형