리액트 페이지네이션 구현하기(React pagination) (1)
🚩 페이지네이션
웹 페이지에서 게시판 밑에 보면 1, 2, 3, 4,… 로 페이지 번호를 매겨 놓은 모습을 아주 흔하게 보실 수 있습니다.
(출처 : 다음 뉴스 게시판)
이러한 페이지네이션을 React hook인 useState, useEffect와 자바스크립트 array 메소드인 slice를 활용해 간단하게 구현하는 방법을 알아보겠습니다.
📘 1. 리액트 프로젝트 생성
리액트 프로젝트 관련 설정 및 초기 생성법 : https://chanhuiseok.github.io/posts/react-2/
아래 명령어를 통해 리액트 프로젝트를 생성합니다.
1
$ yarn create react-app myDirName
생성 후 해당 디렉토리로 이동합니다.
1
$ cd myDirName
📘 2. 연습용 데이터 가져오기
일단 불필요한 파일들은 먼저 삭제해 보겠습니다. 생성한 리액트 프로젝트에서 아래 파일들을 삭제해 주세요.
App.test.js, reportWebVitals.js, setupTests.js
온라인에서 별도의 키값이 없어도 연습용으로 REST API를 제공하는 사이트가 많습니다.
그 중에서 저는 https://jsonplaceholder.typicode.com/ 사이트를 사용하겠습니다.
사용할 주소 : https://jsonplaceholder.typicode.com/posts
이 주소에 접속해 보면 위와 같이 100개의 데이터를 json 형태로 받아옴을 확인할 수 있습니다.
이제 App.js에 들어가서 코드를 수정합니다. 그 전에, axios와 styled-components 먼저 설치합니다.
1
2
$ yarn add axios
$ yarn add styled-components
axios는 자바스크립트에서 Promise를 기반으로 하여 비동기 처리를 도와줍니다. axios는 받아온 json 데이터를 알아서 변환해 주기도 하고, 크로스 브라우징에서도 효과적이어서 많이 쓰인다고 합니다.
styled-components는 리액트에서 CSS-in-JS를 실현하게 해 주는 라이브러리입니다. 여기서도 간단하게 컴포넌트 단위의 디자인을 설정하기 위해 설치하였습니다.
이제 App.js 코드를 수정합니다. 데이터를 잘 받아오는지 테스트 하는 과정입니다.
아래에서 사용한 hook 및 각종 함수들에 대한 설명은 하단에 작성하였습니다.
useState hook 알아보기 : https://chanhuiseok.github.io/posts/react-6/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import "./App.css";
import React, { useState, useEffect } from "react";
import axios from "axios";
function App() {
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(false);
const [currentPage, setCurrentPage] = useState(1);
const [postsPerPage, setPostsPerPage] = useState(10);
useEffect(() => {
const fetchData = async () => {
setLoading(true);
const response = await axios.get(
"https://jsonplaceholder.typicode.com/posts"
);
setPosts(response.data);
setLoading(false);
};
fetchData();
}, []);
console.log(posts);
return <div className="App"></div>;
}
export default App;
- App은 함수형 컴포넌트로 작성되었습니다. 따라서, useState나 useEffect와 같은 hook을 사용한 것입니다.
- (6~9행) posts, loading, currentPage, postsPerPage state를 지정하였습니다. posts state에는 실제 json 데이터들이 array 형태로 들어오므로 초기값을 배열 리터럴(
[]
)로 두었습니다. - (11~18행) useEffect hook을 작성한 모습입니다.
- (12~16행) async, await, axios로 데이터를 가져오는 모습입니다. useEffect hook은 특정한 작업을 렌더링(마운트)할 때마다 사용할 경우 사용합니다. 첫 번째 인자에 작성한 함수를 작업으로 실행합니다. 두 번째 인자에
[]
를 두었는데, 이렇게 하면 컴포넌트가 맨 처음 렌더링(마운트)될 때만 useEffect에 정의한 내용을 실행하게 됩니다. - 익명 함수 앞에 async를 붙여서 이 부분은 비동기 처리를 하는 곳이라고 알립니다. 밑에서 axios.get 이 반환하는 것은 Promise 객체인데요, 그 앞에 await를 붙여서 프로미스가 반환될 때까지 기다립니다.
- 이를 기다리는 동안 자바스크립트 엔진은 다른 일들을 처리할 수 있습니다. 그래서 비동기 처리를 도와주는 문법이라는 것입니다.
- 참고로, await은 반드시 async로 정의한 함수 내부에서만 사용할 수 있습니다.
- async, await 구문은 promise 객체가
.then
으로 콜백을 처리하던 부분을 좀 더 깔끔하게 작성할 수 있게 해 줍니다. - 받아온 데이터를 setPosts 를 통해 posts state에 넣어주었습니다.
- (12~16행) async, await, axios로 데이터를 가져오는 모습입니다. useEffect hook은 특정한 작업을 렌더링(마운트)할 때마다 사용할 경우 사용합니다. 첫 번째 인자에 작성한 함수를 작업으로 실행합니다. 두 번째 인자에
브라우저 콘솔에 데이터가 뜨는지 확인해 볼까요?
이렇게 100개의 포스트를 정상적으로 받아온 것을 확인할 수 있습니다.
📘 3. 페이지에 내용을 표시하기
받아온 데이터를 콘솔이 아니라 웹 페이지에 표시해 보려고 합니다.
리액트에서 컴포넌트 단위로 작성하는 방법을 연습하기 위해, 데이터가 표시되는 컴포넌트를 Posts
로 정의하여 간단하게 작성해 보겠습니다.
📜 Posts.js 생성 및 작성
React map 함수 사용법 : https://chanhuiseok.github.io/posts/react-8/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import React from "react";
const Posts = ({ posts, loading }) => {
return (
<>
{loading && <div> loading... </div>}
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</>
);
};
export default Posts;
- Posts 컴포넌트는 인자로 posts, loading을 넘겨받습니다.
- posts는 데이터이고, loading은 데이터가 아직 로딩되지 않았을 경우를 처리합니다.
- { loading && … } 부분은, loading 값이 true일 때 && 다음의 것을 표시한다는 의미입니다.
- 자바스크립트의 map 함수를 사용하여 여러 데이터들을 표시합니다. posts 라는 배열에 담긴 값을 하나씩
post
로 빼와서<li>
로 만들어 보여 줍니다. - 이 때 map 함수로 여러 요소를 그릴 때는, 해당 요소에 key 값을 사용해야 합니다. 데이터에서 키로 구분이 될 만한 값은 id 입니다. 따라서 그려주는 요소에 key를
{post.id}
값으로 전달한 것입니다.
📜 App.js 수정
위에서 만든 Posts 컴포넌트를 사용합니다. Posts 를 import 하고, return문 안에서 사용합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import "./App.css";
import React, { useState, useEffect } from "react";
import axios from "axios";
import Posts from "./Posts";
function App() {
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(false);
const [currentPage, setCurrentPage] = useState(1);
const [postsPerPage, setPostsPerPage] = useState(10);
useEffect(() => {
const fetchData = async () => {
setLoading(true);
const response = await axios.get(
"https://jsonplaceholder.typicode.com/posts"
);
setPosts(response.data);
setLoading(false);
};
fetchData();
}, []);
console.log(posts);
return (
<div className="App">
<Posts posts={posts} loading={loading}></Posts>
</div>
);
}
export default App;
다시 실행해 보면 웹 페이지에 아래와 같이 데이터가 출력됩니다.
이제 이 데이터들을 정해진 페이지단위에 맞게 페이지네이션을 하는 작업만 남았습니다.
다음 포스팅에서 이어서 작성하겠습니다!