해당 내용:
Array.from()
참고할 글
[리액트] 페이지 함수 만들기 (tistory.com)
App.js
import React, { useState } from 'react';
import Pagination from './Pagination'; // Pagination 컴포넌트 가져오기
function App() {
// 페이지 상태 정의
const [currentPage, setCurrentPage] = useState(1); // 현재 페이지 상태
const totalPages = 3; // 총 페이지 수 (예시로 3페이지로 설정)
// 페이지 변경 핸들러
function handlePageChange(page) {
setCurrentPage(page); // 페이지를 변경할 때 상태를 업데이트
}
return (
<div className="App">
{/* 다른 컴포넌트와 콘텐츠들 */}
<Pagination
currentPage={currentPage}
totalPages={totalPages}
onPageChange={handlePageChange}
/>
</div>
);
}
export default App;
설명
1. 상태 정의:
const [currentPage, setCurrentPage] = useState(1);
-
- currentPage: 현재 페이지 번호를 저장하는 상태입니다. 초기값으로 1을 설정합니다.
- setCurrentPage: currentPage 상태를 업데이트하는 함수입니다. 페이지를 변경할 때 호출됩니다.
2. 총 페이지 수:
const totalPages = 3;
totalPages: 페이지 수를 설정합니다. 이 예제에서는 총 3페이지로 설정했습니다.
3. 페이지 변경 핸들러: ★☆
function handlePageChange(page) {
setCurrentPage(page);
}
handlePageChange 함수는 페이지 번호를 인수로 받아,
setCurrentPage를 호출하여 currentPage 상태를 업데이트합니다.
page 에 대해서 >
handlePageChange 함수에서 사용된 page는 함수의 매개변수(parameter)입니다.
이 매개변수는 함수가 호출될 때 전달되는 값을 의미합니다. 좀 더 자세히 설명해볼게요.
매개변수(파라미터)와 인수(아규먼트) >
매개변수(파라미터):
함수 정의에서 function handlePageChange(page)와 같은 형태로 함수가 정의될 때,
page는 매개변수입니다.
매개변수는 함수가 호출될 때 외부에서 값을 받을 준비가 되어 있는 변수입니다.
* 매개변수 이름은 자유롭게 설정 가능
인수(아규먼트): 함수 호출 시 실제로 전달되는 값입니다.
예를 들어, handlePageChange(2)를 호출하면 2는 page 매개변수에 전달됩니다.
이때 page는 2라는 값을 갖게 됩니다.
handlePageChange 함수: 이 함수는 page라는 매개변수를 받아서 setCurrentPage를 호출합니다.
page 매개변수: 이 값은 페이지 번호를 나타냅니다.
handlePageChange가 호출될 때 이 매개변수는 함수 호출 시 전달된 페이지 번호로 설정됩니다.
setCurrentPage(page): page 값을 setCurrentPage 함수에 전달하여 currentPage 상태를 업데이트합니다.
예를 들어, page가 2로 설정되면 currentPage 상태가 2로 변경됩니다.
함수 호출 예시 >
// 페이지 변경 버튼 클릭 시
<button onClick={() => handlePageChange(2)}>Page 2</button>
- 이 버튼을 클릭하면 handlePageChange(2)가 호출됩니다.
- 여기서 page 매개변수는 2로 설정되고,
- setCurrentPage(2)가 호출되어 currentPage 상태가 2로 업데이트됩니다.
정리
- 매개변수는 함수 정의에서 사용되는 변수로, 함수 호출 시 값을 받을 준비가 되어 있습니다.
- 인수는 함수 호출 시 전달되는 실제 값입니다.
매개변수는 함수의 동작을 결정하는 데 필요한 정보를 외부에서 함수로 전달하는 방법입니다.
이 정보를 기반으로 함수는 동작을 수행하고 결과를 반환합니다.
4. Pagination 컴포넌트 렌더링:
<Pagination
currentPage={currentPage}
totalPages={totalPages}
onPageChange={handlePageChange}
/>
Pagination 컴포넌트에 currentPage, totalPages, onPageChange를 props로 전달합니다.
currentPage: 현재 페이지 번호를 전달합니다.
totalPages: 총 페이지 수를 전달합니다.
onPageChange: 페이지가 변경될 때 호출될 함수(handlePageChange)를 전달합니다.
이 구조에서 App 컴포넌트는 페이지 상태를 관리하고,
Pagination 컴포넌트는 페이지네이션 UI를 담당합니다.
Pagination 컴포넌트가 페이지 번호를 표시하고,
페이지 변경을 처리하면 App 컴포넌트는 페이지 상태를 업데이트하여 UI를 새로 렌더링합니다.
헷갈리는 handlePageChange 함수 알아보기
- 매개변수(파라미터)와 인수의 차이
page는 매개변수(parameter)입니다.
함수가 정의될 때, 함수가 외부에서 어떤 값을 받을 준비를 하는 변수입니다.
그리고 함수가 실제로 호출될 때, 그 매개변수로 전달되는 값이 인수(argument)라고 부릅니다.
간단하게 정리하자면:
- 매개변수: 함수가 정의될 때, 받을 값을 가리키는 변수 이름. 함수가 호출될 때,
- 그 이름으로 값을 받을 준비를 하고 있는 상태.
- 인수: 함수가 호출될 때, 실제로 전달된 값.
예시로 이해하기
- 매개변수: 함수에서 page라고 이름 붙인 것.
- 인수: 이 함수가 호출될 때, 함수에 전달되는 실제 값.
function handlePageChange(page) { // page는 매개변수
setCurrentPage(page); // setCurrentPage에 매개변수 page를 전달하여 상태 업데이트
}
handlePageChange(2); // 이때 2가 인수
- 함수가 정의된 부분에서 page는 매개변수입니다.
- 즉, 함수가 호출될 때 이 자리에 어떤 값이 들어올지 미리 지정해둔 이름입니다.
- handlePageChange(2)라고 호출하면, 2는 인수입니다.
- 이 인수가 page라는 매개변수로 들어가서 함수 안에서 사용됩니다.
- 매개변수 (page):
- handlePageChange(page)에서 page는 매개변수입니다.
- 이 함수는 호출될 때 page라는 이름으로 값을 받을 준비를 하고 있습니다.
- 인수 (2):
- 나중에 handlePageChange(2)라고 함수가 실제로 호출될 때, 2라는 값이 전달됩니다.
- 이 2가 함수로 들어가는 인수입니다.
- 매개변수 (page):
간단한 비유
- 매개변수: 빈 상자에 이름을 붙여 놓는 것 (예: page).
- 인수: 상자를 사용할 때 그 안에 넣는 실제 값 (예: 2).
따라서 page는 매개변수이며, handlePageChange(2)처럼 호출될 때 2라는 값이 인수로 들어가게 되는 거죠.
1. 매개변수 (Parameter)
- 매개변수는 함수를 정의할 때 함수가 받을 값을 지정하는 이름입니다.
- 예를 들어, function handlePageChange(page)에서 page는 매개변수입니다.
- 이 함수가 호출될 때 외부에서 전달받을 값을 받을 준비를 하는 상자 같은 것이죠.
- 하지만 이 시점에서는 page 안에 뭐가 들어갈지 아직 모릅니다.
2. 인수 (Argument)
- 인수는 함수를 실제로 호출할 때 전달되는 실제 값입니다.
- 예를 들어, handlePageChange(2)라고 하면 여기서 2는 인수입니다.
- 이제 page라는 매개변수가 2라는 값을 받게 됩니다.
다시 풀어서 설명
- **매개변수 (parameter)**는 함수가 받을 상자의 이름입니다.
- **인수 (argument)**는 함수가 호출될 때 상자 안에 들어가는 실제 값입니다.
정리
- 함수 정의 시: 매개변수는 함수가 받는 값의 이름 (예: page).
- 함수 호출 시: 인수는 함수로 전달되는 실제 값 (예: 2).
그래서 handlePageChange(page)에서 page는 매개변수이고,
함수가 호출될 때 인수는 그 매개변수로 들어가는 값이죠.
함수도 props 로 보낼 수 있음
- state 만 보낼 수 있는 것 아님.
<Pagination currentPage={currentPage} totalPages={totalPages} onPageChange={handlePageChange} />
Paginaton 컴포넌트에 props 를 보내기 위해
handlePageChange 함수를 작명했다.
함수도 props로 전달할 수 있습니다.
실제로 handlePageChange 함수도 props로 Pagination 컴포넌트에 전달되고 있죠.
함수도 props로 전달하는 이유
리액트에서 props는 부모 컴포넌트가 자식 컴포넌트로 데이터나 동작을 전달할 때 사용합니다.
데이터를 전달하는 것뿐만 아니라, 부모 컴포넌트에서 정의한 함수를 자식 컴포넌트에 전달해서,
자식 컴포넌트가 그 함수를 호출할 수 있게 만드는 겁니다.
즉, 상태뿐만 아니라 함수도 props로 전달할 수 있습니다.
- currentPage={currentPage}: 현재 페이지 번호(currentPage)라는 상태를 Pagination 컴포넌트로 전달합니다.
- totalPages={totalPages}: 총 페이지 수(totalPages)를 Pagination 컴포넌트로 전달합니다.
- onPageChange={handlePageChange}: 부모 컴포넌트(App.js)에서 정의한 handlePageChange라는 함수를 자식 컴포넌트인 Pagination에 전달합니다.
이름을 state 처럼 동일하게 짓지 않은 이유
리액트에서는 onClick, onChange처럼 이벤트와 관련된 함수는
보통 on으로 시작하는 이름을 쓰는 패턴이 많기 때문에, 함수 이름을 onPageChange로 지어준 것
함수 이름을 동일하게 짓지 않은 이유
예를 들어, handlePageChange라는 부모 컴포넌트에서의 함수 이름을
자식 컴포넌트에 그대로 전달하지 않고 onPageChange라고 지은 이유는:
- 의도를 명확히 하기 위해:
- **handlePageChange**는 부모 컴포넌트에서 페이지를 변경하는 함수를 정의할 때 사용한 이름입니다.
- **onPageChange**는 자식 컴포넌트(Pagination) 입장에서, 페이지가 변경될 때(on) 무언가를 해야 한다는 의미를 전달합니다.
- 역할에 맞는 이름 짓기:
- 부모 컴포넌트에서 handlePageChange는 페이지가 변경될 때 상태를 업데이트하는 역할을 합니다.
- 자식 컴포넌트에서는 이 함수가 페이지 변경 시 실행되는 함수라는 의미를 전달하고 싶습니다. 그래서 자식에서는 onPageChange라고 이름을 지어주는 것이 더 자연스럽습니다.
그렇다고 해서 항상 다르게 지어야 하는 건 아닙니다. 동일하게 지어도 됩니다. 다음과 같이 작성할 수도 있어요:
정리
- 같은 이름을 써도 문제가 없어요.
- 그러나 자식 컴포넌트의 역할이나 이벤트 맥락에 맞춰 onPageChange처럼
- 역할을 강조하는 이름을 주는 것이 일반적인 패턴입니다.
- 리액트에서는 이벤트와 관련된 함수는 보통 on으로 시작하는 이름을 많이 씁니다.
- 그래서 handlePageChange가 아닌 onPageChange라고 이름을 지은 거죠.
Page 컴포넌트 수정해주기
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faAngleLeft, faAngleRight } from "@fortawesome/free-solid-svg-icons";
function Pagination({ currentPage, totalPages, onPageChange }) {
// 이전 페이지로 이동하는 함수
function handlePrevClick(event) {
event.preventDefault();
if (currentPage > 1) {
onPageChange(currentPage - 1); // 페이지를 하나 줄여서 호출
}
}
// 다음 페이지로 이동하는 함수
function handleNextClick(event) {
event.preventDefault();
if (currentPage < totalPages) {
onPageChange(currentPage + 1); // 페이지를 하나 늘려서 호출
}
}
return (
<div className="pagination">
{/* 이전 페이지 버튼 */}
<a
href="#"
onClick={handlePrevClick}
className={currentPage === 1 ? "disabled" : ""}
>
<FontAwesomeIcon icon={faAngleLeft} />
</a>
{/* 페이지 번호 목록 */}
<ol>
{Array.from({ length: totalPages }, (_, index) => (
<li key={index}>
<a
href="#"
className={currentPage === index + 1 ? "active" : ""}
onClick={(event) => {
event.preventDefault();
onPageChange(index + 1); // 클릭한 페이지 번호로 이동
}}
>
{index + 1}
</a>
</li>
))}
</ol>
{/* 다음 페이지 버튼 */}
<a
href="#"
onClick={handleNextClick}
className={currentPage === totalPages ? "disabled" : ""}
>
<FontAwesomeIcon icon={faAngleRight} />
</a>
</div>
);
}
export default Pagination;
이 코드의 역할
이 Pagination 컴포넌트는 페이지네이션(페이지 이동)을 구현한 것입니다.
여러 페이지가 있을 때, 사용자가 특정 페이지로 이동할 수 있도록
이전 페이지, 다음 페이지 버튼을 제공하고,
가운데에 각 페이지 번호를 보여줍니다.
코드의 주요 부분 설명
props로 받아오는 값들
- App.js 에서 받아옴
- currentPage: 현재 선택된 페이지 번호를 의미합니다. 예를 들어, 현재 페이지가 2라면 currentPage는 2입니다.
- totalPages: 총 몇 페이지가 있는지를 나타냅니다. 예를 들어, 페이지가 5개라면 totalPages는 5입니다.
- onPageChange: 사용자가 페이지 번호를 클릭하거나, "이전", "다음" 버튼을 눌렀을 때 어떤 페이지로 이동할지 알려주는 함수입니다.
이전 페이지로 이동하는 함수 (handlePrevClick)
function handlePrevClick(event) {
event.preventDefault(); // 링크 클릭 시 페이지 새로고침 방지
if (currentPage > 1) {
onPageChange(currentPage - 1); // 이전 페이지로 이동
}
}
- 이 함수는 "이전 페이지" 버튼을 눌렀을 때 실행됩니다.
- currentPage(현재 페이지) > 1인 경우에만 실행되며,
- 첫 페이지(페이지 1)에서는 이전 페이지가 없으므로 아무 동작도 하지 않도록 되어 있습니다.
- onPageChange(currentPage - 1)을 통해 현재 페이지에서 1을 뺀 값(이전 페이지)을 부모 컴포넌트에 알려줍니다.
event.preventDefault(); 을
사용한 이유 👉
event.preventDefault();를 사용한 이유는 페이지 새로고침을 막기 위해서입니다.
리액트에서 <a> 태그는 기본적으로 링크 역할을 합니다.
링크를 클릭하면 브라우저는 해당 페이지를 새로고침하거나 링크된 URL로 이동하려고 합니다.
하지만, 페이지네이션에서 우리는 링크를 클릭해도 새 페이지로 이동하지 않고,
자바스크립트 코드만 실행되기를 원하죠.
즉, "이전 페이지" 버튼을 눌렀을 때 페이지 전체를 새로고침하지 않고
자바스크립트 로직(handlePrevClick 함수)만 실행되도록 하기 위해 event.preventDefault()를 사용합니다.
이 함수는 이벤트의 기본 동작을 막는 역할을 하며,
이 경우에는 링크 클릭 시 발생하는 페이지 이동 또는 새로고침을 방지하는 것입니다.
event.preventDefault()는 실제 페이지 새로고침을 막고,
리액트에서 페이지 번호만 바꾸는 방식으로 "페이지 이동"을 처리하는 거예요.
SPA에서는 페이지 전체를 새로고침하지 않고도 **페이지네이션(이전/다음 페이지)**을 구현할 수 있어서, event.preventDefault()로 새로고침을 방지하는 것이 중요합니다.
event.preventDefault(); 의 사용 방법
- e.preventDefault(); 와의 차이
👉
event.preventDefault() 와 e.preventDefault()는 사실 같은 메서드입니다.
둘 다 이벤트의 기본 동작을 방지하는 역할을 하며,
이벤트 객체의 메서드를 호출하는 방법에 따라 이름만 다를 뿐입니다.
차이점:
이벤트 객체의 이름:event와 e는 이벤트 객체를 나타내는 이름일 뿐입니다.
이름은 개발자가 정하는 것으로, 이벤트 객체를 가리킵니다.
event라는 이름은 자주 사용되지만, e는 짧고 간결해서 많이 사용됩니다.
두 이름 모두 같은 기능을 수행합니다.
메서드의 역할:
event.preventDefault()와 e.preventDefault()는 기능상 차이가 없습니다.
둘 다 이벤트의 기본 동작을 방지합니다.
예를 들어, 링크 클릭 시 페이지 이동을 막고 싶을 때 사용됩니다.
if (currentPage > 1) { onPageChange(currentPage - 1);
코드 상세 해석 👉
현재 페이지가 1보다 클 때만 실행되도록 만들어진 것
if (currentPage > 1)
이 부분은 "지금 내가 보고 있는 페이지가 첫 번째 페이지가 아닌 경우"를 체크하는 거예요.
예를 들어, 현재 페이지가 2, 3, 4...일 때는 이 조건이 참(true)이 되고,
이 안에 있는 코드가 실행돼요.
만약 현재 페이지가 1이라면, 더 이상 이전 페이지가 없잖아요?
그래서 첫 페이지에서는 이 코드가 실행되지 않도록 조건을 넣은 거예요.
onPageChange(currentPage - 1)
이 부분은 "지금 페이지에서 이전 페이지로 이동하라"는 뜻이에요.
예를 들어, 현재 페이지가 3이라면 currentPage - 1은 2가 되겠죠?
그래서 "이전 페이지인 2로 가라"는 의미가 됩니다.
이때 onPageChange라는 함수가 부모 컴포넌트에서 전달된 건데,
이 함수가 실행되면 부모 컴포넌트에서 페이지를 바꿔주는 일을 해요.
※ if문의 조건에 부합하면, props로 받아온 onPageChange 함수가 실행되는 것
동작 원리:
if (currentPage > 1) 조건:
현재 페이지가 1보다 큰 경우에만
이 코드 안쪽의 onPageChange(currentPage - 1)가 실행돼요.
예를 들어, 현재 페이지가 3이면, 1보다 크기 때문에 이 조건에 맞아 실행됩니다.
onPageChange(currentPage - 1):
이 onPageChange는 **부모 컴포넌트(App.js)**에서 props로 전달된 함수예요.
이 함수는 currentPage - 1 (즉, 이전 페이지 번호)을 인수로 받아서,
부모 컴포넌트의 상태를 업데이트하는 역할을 합니다.
onPageChange가 호출되면,
실제로는 부모 컴포넌트(App.js)에 있는 handlePageChange 함수가 실행됩니다.
이 함수는 새로운 페이지 번호를 받아서 currentPage 상태를 업데이트해요.
전체 과정:
onPageChange(currentPage - 1) 호출 :
Pagination 컴포넌트에서 이전 페이지로 이동하려고 할 때,
onPageChange 함수를 호출합니다.
이때 인수로 currentPage - 1을 전달합니다.
부모 컴포넌트의 함수 호출 :
onPageChange는 부모 컴포넌트에서 전달된 함수입니다.
예를 들어, App.js에서는 handlePageChange라는 함수가 onPageChange로 전달됩니다.
onPageChange가 호출되면서 전달된 인수(currentPage - 1)가
handlePageChange 함수의 page 파라미터로 들어갑니다.
여기서 page는 onPageChange를 통해 전달된 인수입니다.
예를 들어, currentPage가 3이라면 onPageChange(2)가 호출되고,
이때 2가 page 파라미터로 전달됩니다.
setCurrentPage(page)를 호출하여 page 값을 현재 페이지 상태로 설정합니다.
즉, currentPage가 2로 업데이트됩니다.
요약:
인수는 함수 호출 시 함수에 전달되는 값입니다.
파라미터는 함수 정의 시 값이 들어올 자리입니다.
인수가 함수의 파라미터로 전달되어, 함수 내에서 그 값을 사용하여 필요한 작업을 수행합니다.
그래서 onPageChange(currentPage - 1)에서 currentPage - 1은 인수로서
handlePageChange(page)의 page 파라미터로 들어가고,
이 값을 사용하여 페이지 상태를 업데이트하는 것이죠!
( 약간 인수와 매개변수는 마법 포탈같은 느낌 )
인수 (Argument): 포탈을 통해 들어오는 값. 함수를 호출할 때 이 값이 실제로 전달되는 것
매개변수 (Parameter): 포탈 안에서 값이 들어올 자리.
함수 정의에서 자리를 잡고 있는 것처럼, 값을 받을 준비가 된 상태.
함수 호출 시 인수가 매개변수로 들어가면, 함수 안에서 그 값을 활용하여 원하는 작업을 수행.
마법처럼 값이 전달되어 결과를 만들어내는 과정
다음 페이지로 이동하는 함수 (handleNextClick)
function handleNextClick(event) {
event.preventDefault();
if (currentPage < totalPages) {
onPageChange(currentPage + 1); // 다음 페이지로 이동
}
}
- 이 함수는 "다음 페이지" 버튼을 눌렀을 때 실행됩니다.
- 현재 페이지가 마지막 페이지가 아니라면, currentPage + 1로 다음 페이지로 이동하도록 합니다.
if (currentPage < totalPages) { onPageChange(currentPage + 1);
코드 상세 해석 👉
현재 페이지가 마지막 페이지보다 작을 때만 다음 페이지로 이동하도록 하는 함수
단계별로 설명하기:
- 조건문: if (currentPage < totalPages)
예를 들어:
- 여기서 currentPage는 현재 사용자가 보고 있는 페이지 번호입니다.
- totalPages는 전체 페이지의 수를 나타냅니다.
- 이 조건문은 현재 페이지가 전체 페이지 수보다 작으면(즉, 아직 마지막 페이지가 아니라면)
다음 페이지로 이동하라는 의미입니다.
- currentPage가 3이고, totalPages가 5라면 조건이 참이 됩니다.
- 즉, 아직 마지막 페이지(5페이지)에 도달하지 않았으니, 다음 페이지로 이동할 수 있다는 뜻입니다.
- onPageChange(currentPage + 1)
- onPageChange는 페이지를 변경하는 함수입니다.
- 이 부분에서는 현재 페이지보다 1을 더한 값을 onPageChange 함수에 전달합니다.
예를 들어, 현재 페이지가 3이라면 다음 페이지인 4로 이동하게 됩니다.- 이 함수가 호출되면 다음 페이지로 넘어가게 됩니다.
전체 과정 비유:
- 상상해보세요. 책을 읽고 있는데, 현재 3쪽을 보고 있고, 책은 총 5쪽까지 있어요.
- 조건문은 "현재 3쪽인데 책이 5쪽까지 있으니, 다음 쪽을 봐도 괜찮아!"라고 말하는 것과 같아요.
- **onPageChange(currentPage + 1)**은 "다음 쪽으로 넘어가라"는 신호를 보내는 역할을 합니다.
그래서 책의 4쪽으로 넘어갑니다.요약:
- currentPage < totalPages: 현재 페이지가 전체 페이지보다 작으면, 즉 마지막 페이지가 아니라면,
- onPageChange(currentPage + 1): 현재 페이지보다 하나 더 큰 페이지(다음 페이지)로 이동하라는 뜻입니다.
HTML 구조
<div className="pagination">
이 div는 페이지네이션 컴포넌트를 감싸는 기본 틀입니다.
이전 페이지 버튼
<a
href="#"
onClick={handlePrevClick}
className={currentPage === 1 ? "disabled" : ""}
>
<FontAwesomeIcon icon={faAngleLeft} />
</a>
- <a> 태그는 이전 페이지로 가기 위한 버튼입니다.
- onClick={handlePrevClick}: 이 버튼을 클릭하면 handlePrevClick 함수 (이전페이지 버튼 함수)가 실행됩니다.
- className={currentPage === 1 ? "disabled" : ""}:
- 현재 페이지가 1이면 버튼을 비활성화하기 위해 disabled 클래스를 추가합니다.
- FontAwesomeIcon으로 이전 화살표 아이콘을 표시합니다.
각 부분 설명
- <a href="#">:
- <a> 태그는 일반적으로 링크를 만들 때 사용하는 태그예요.
- href="#"는 페이지의 상단으로 이동하는 기본 동작을 의미하지만,
- 여기서는 이 동작을 막기 위해 event.preventDefault()를 나중에 사용합니다.
- onClick={handlePrevClick}:
- 사용자가 이 버튼(링크)을 클릭했을 때 handlePrevClick 함수를 실행하라는 뜻입니다.
- handlePrevClick 함수는 이전 페이지로 이동하는 기능을 담당하고 있어요.
- 버튼을 클릭하면 이 함수가 호출되어 현재 페이지에서 이전 페이지로 이동하는 작업이 실행됩니다.
- className={currentPage === 1 ? "disabled" : ""}:
- 이 부분은 조건부로 클래스 이름을 적용하는 코드입니다.
- currentPage === 1은 현재 페이지가 1일 때만 disabled라는 클래스를 추가해줍니다.
- 즉, 현재 1페이지라면 더 이상 이전 페이지가 없으므로, 버튼을 비활성화(클릭할 수 없도록) 시킵니다.
- 만약 현재 페이지가 1이 아니라면, 클래스 이름에 아무것도 추가하지 않아요.
- disabled 클래스는 CSS로 버튼을 회색으로 바꾸거나 클릭할 수 없도록 스타일을 줄 때 자주 사용됩니다.
- <FontAwesomeIcon icon={faAngleLeft} />:
- 이 부분은 왼쪽 화살표 아이콘을 표시합니다.
- faAngleLeft는 Font Awesome 라이브러리에서 제공하는 왼쪽 화살표 모양의 아이콘입니다.
- 즉, "이전 페이지"를 의미하는 화살표를 시각적으로 보여주는 역할을 합니다.
비유로 설명하기
이 코드를 버튼으로 비유하면, 이 버튼은 "이전 페이지로 돌아가라"는 역할을 하는데,
첫 페이지에 있을 때는 비활성화되어 작동하지 않도록 만들어졌어요.
- 누르면: onClick으로 handlePrevClick 함수가 실행돼요.
- 조건에 따라: 현재 페이지가 1이면, 버튼이 disabled 상태가 되어 클릭할 수 없도록 보여줍니다.
- 아이콘으로 표시: 왼쪽 화살표 아이콘을 통해 사용자가 쉽게 이전 페이지로 가는 버튼임을 알 수 있어요.
요약
- 이 버튼을 누르면 이전 페이지로 이동하려고 하고,
- 만약 현재 페이지가 1페이지라면 버튼이 비활성화되어 클릭할 수 없게 만들어졌습니다.
- 왼쪽 화살표 아이콘이 시각적으로 버튼의 역할을 나타내 줍니다.
className={currentPage === 1 ? "disabled" : ""}:
이 코드 분석 👉
className={조건 ? "클래스명" : ""} 같은 방식은 리액트에서 자주 사용되는 패턴이에요.
특히 조건부로 CSS 클래스를 적용할 때 매우 유용해요.
이 방법을 사용하면, 특정 상태나 조건에 따라 동적으로 스타일을 적용할 수 있거든요.언제 많이 쓰이나요?
- 버튼 비활성화:
- 예를 들어, 현재 페이지가 1일 때는 이전 버튼을 비활성화하거나,
마지막 페이지에서는 다음 버튼을 비활성화할 때 사용됩니다.- 상태에 따른 스타일 변경:
- 예를 들어, 사용자가 특정 입력을 완료하면 버튼 색상을 변경하거나,
에러가 발생하면 빨간 테두리를 추가하는 경우에 쓸 수 있어요.- 선택된 항목 강조:
- 네비게이션 메뉴에서 현재 선택된 항목을 강조 표시하는 데도 많이 사용됩니다.
- className={currentMenu === "home" ? "active" : ""}처럼,
현재 선택된 메뉴에만 active 클래스를 적용하는 방식이죠.// 버튼 비활성화 예시 <button className={isDisabled ? "disabled" : ""}>Click Me</button> // 선택된 항목 강조 예시 <div className={isSelected ? "highlighted" : ""}>Selected Item</div>
장점
- 깔끔한 코드: 조건문을 JSX 안에서 바로 작성할 수 있어서, 불필요하게 많은 줄을 차지하지 않아요.
- 동적 스타일링: 상태나 조건에 따라 실시간으로 스타일을 유연하게 바꿀 수 있어서,
리액트의 장점을 극대화해요.요약
이 방식은 리액트에서 매우 자주 쓰이는 패턴이니 앞으로 자주 보게 될 거예요.
상태나 조건에 따라 스타일을 동적으로 적용할 수 있다는 점에서 정말 편리해요. 😊
페이지 번호 목록
<ol>
{Array.from({ length: totalPages }, (_, index) => (
<li key={index}>
<a
href="#"
className={currentPage === index + 1 ? "active" : ""}
onClick={(event) => {
event.preventDefault();
onPageChange(index + 1);
}}
>
{index + 1}
</a>
</li>
))}
</ol>
- 페이지 번호를 동적으로 생성합니다.
- Array.from({ length: totalPages })는 총 페이지 수만큼의 배열을 만들어
- totalPages에 해당하는 만큼 페이지 번호를 렌더링합니다.
- index + 1: 배열의 index는 0부터 시작하므로, 페이지 번호는 index + 1로 계산됩니다.
- className={currentPage === index + 1 ? "active" : ""}: 현재 페이지 번호와 일치하는 <a> 태그에 active 클래스를 추가해 현재 페이지를 강조합니다.
- 클릭하면 onPageChange(index + 1)가 호출되어 해당 페이지로 이동합니다.
1. Array.from(): 배열 생성
Array.from()은 배열을 만들기 위한 함수예요.
여기서 Array.from({ length: totalPages })는 페이지 수(totalPages)만큼 배열을 만드는 것이죠.
- 예를 들어, totalPages가 3이면 [undefined, undefined, undefined]처럼 3개의 빈 칸이 있는 배열을 만드는 거예요.
Array.from({ length: totalPages })
// totalPages = 3일 경우 -> [undefined, undefined, undefined]
Array.from()은 배열을 만드는 메서드이고,
소괄호 안에 중괄호를 써주는 것은 Array.from()이 객체를 배열로 변환할 때 자주 사용하는 패턴이에요
Array.from({ length: totalPages }) 에서 중괄호 는 객체를 나타내고,
이 객체의 length 속성을 사용해서 원하는 길이만큼의 배열을 만들게 되는 거예요.
이 경우, 배열의 각 요소는 기본값으로 undefined 가 됩니다.
**객체(Object)**는 자바스크립트에서 가장 중요한 데이터 구조 중 하나예요. 객체는 여러 값을 하나로 묶어서 관리할 수 있는 구조로, 키-값(Key-Value) 쌍으로 데이터를 저장합니다. 객체의 기본 구조 객체는 **중괄호 {}**로 감싸고, 그 안에 **키(key)**와 **값(value)**을 쌍으로 정의해요. 키는 고유한 이름이고, 값은 그 키에 연결된 데이터입니다 다시 Array.from()로 돌아가서... Array.from({ length: totalPages })에서 **{ length: totalPages }**는 객체예요. 이 객체는 length라는 키에 totalPages라는 값을 넣어서 정의한 거예요. 여기서 **키(key)**는 length이고, **값(value)**는 totalPages라는 숫자예요. 이걸 통해 Array.from()은 totalPages 길이만큼 배열을 생성하게 되는 거예요. 요약하자면: **객체(Object)**는 여러 데이터를 키-값 쌍으로 저장하는 데이터 구조. { length: totalPages }는 length라는 키에 totalPages 값을 넣은 객체. Array.from({ length: totalPages })는 이 객체의 length 속성을 사용해 배열을 생성하는 것.
굳이 객체를 사용한 이유 >
Array.from({ length: totalPages })에서 굳이 객체를 사용한 이유는
배열을 특정 길이로 만들기 위한 간편한 방법을 제공하기 때문이에요.
객체를 사용하는 게 꼭 필수는 아니지만, 이렇게 작성하는 게 짧고 직관적인 방식이에요.
Array.from()을 사용해서 배열을 만들 때,
객체의 length 속성을 사용하면 원하는 길이만큼의 배열을 만들 수 있어요.
특히 빈 배열을 생성할 때 유용하죠. 여기서 중요한 건 length 속성이에요.
기본값으로 undefined가 되는 이유>
기본값으로 undefined가 되는 이유는 배열이 아직 값을 채우지 않았기 때문이에요1. 배열의 구조
배열은 순서대로 값을 저장하는 자료 구조에요. 하지만 처음 배열을 만들 때는,
그 안에 어떤 값이 들어갈지 아직 정해지지 않았죠.const array = new Array(3); // 길이가 3인 배열 생성 console.log(array); // [undefined, undefined, undefined]
이 코드에서 배열을 만들기만 하고 값을 넣지 않았어요.
이럴 때 자바스크립트는 "아직 값이 없다"는 의미로 **undefined**를 기본값으로 채워 넣어요.2. 왜 undefined가 기본값일까?
undefined는 자바스크립트에서 **"아직 정의되지 않은 값"**을 나타내는 특별한 값이에요.
- 우리가 배열을 만들지만 아직 어떤 값을 넣을지 모를 때,
자바스크립트는 "이 위치에 아직 값이 없지만, 자리만 잡아두겠다"는 의미로 **undefined**를 넣어요.- 즉, 자리를 비워둔 상태를 의미한다고 보면 돼요.
3. 배열의 각 요소에 값이 없으면?
배열을 생성하면서 특정 값으로 채우지 않으면,
자바스크립트는 자동으로 그 자리에 undefined를 넣어 "여기에 값이 아직 없다"는 표시를 해 줘요.const array = Array.from({ length: 5 }); console.log(array); // [undefined, undefined, undefined, undefined, undefined]
여기서도 마찬가지로 길이만 지정하고 값을 넣지 않았으니,
모든 요소가 undefined로 채워지는 거예요.4. 값을 나중에 채워넣으면?
배열을 만들고 나서, 그 안에 값을 넣으면 undefined는 사라지고 새로운 값이 들어가게 돼요.
예시:
const array = Array.from({ length: 3 }); array[0] = 'first'; console.log(array); // ['first', undefined, undefined]
이렇게 배열을 생성하고 값을 넣으면, undefined 대신 원하는 값이 들어가는 거죠!
정리하자면:
- 배열을 만들 때 값이 없으면 기본적으로 **undefined**로 채워져요.
- undefined는 자바스크립트에서 값이 아직 정의되지 않았다는 의미를 가지고 있어요.
- 나중에 값을 넣으면 undefined 대신 새로운 값이 들어가요.
Array.from({ length: totalPages } 이거니까 이미 totalPages 의 값을 알고있으면
undefined 가 안나오는거 아닌가? >totalPages 값이 있다고 해서 undefined가 나오지 않는 것은 아니에요.
이 부분을 조금 더 구체적으로 설명해드릴게요.1. totalPages는 배열의 길이를 설정하는 값
Array.from({ length: totalPages })에서 totalPages는 배열의 길이를 결정하는 역할만 해요.
배열의 각 요소에 어떤 값이 들어가는지와는 관계가 없어요.예를 들어, totalPages가 5라면, 길이가 5인 배열을 만들겠다는 뜻이에요.
하지만 이 배열의 요소에는 값을 따로 넣지 않았기 때문에 기본적으로 undefined로 채워지는 거예요.const array = Array.from({ length: 5 }); console.log(array); // [undefined, undefined, undefined, undefined, undefined]
2. Array.from()의 두 번째 인자를 이용해 값을 채우기사실 Array.from() 함수는 두 번째 인자로 배열의 각 요소에 어떤 값을 넣을지를 결정할 수 있어요.
우리는 이 부분에서 (_, index)를 사용했어요. 여기서 index는 배열의 현재 위치를 가리켜요.Array.from({ length: totalPages }, (_, index) => index + 1);
이렇게 하면 index를 사용해 배열을 1부터 totalPages까지의 숫자로 채울 수 있어요.
결과적으로 배열이 [1, 2, 3, 4, 5]처럼 숫자로 채워지죠.3. 왜 처음에 undefined가 나오나?
Array.from({ length: totalPages })에서, 첫 번째 인자로는 객체의 length만 사용하고,
배열에 넣을 값을 따로 지정하지 않았기 때문에
자바스크립트는 "값이 없다"고 판단해서 undefined로 기본 채우기를 하는 거예요.하지만 우리가 두 번째 인자로 (, index) => index + 1처럼 배열의 값을 어떻게 만들지 알려주면,
undefined 대신 지정한 값으로 채워지게 되는 거죠.요약:
- totalPages는 배열의 길이를 정하는 역할만 해요.
- 배열에 값을 넣지 않으면 기본적으로 undefined로 채워져요.
- Array.from()의 두 번째 인자를 사용해서 각 요소에 값을 직접 넣을 수 있어요.
Array.from({ length: totalPages }, (_, index) => index + 1);
쉽게 이해하기 >1. 배열 만들기
우리가 하고 싶은 것은 숫자가 들어있는 배열을 만드는 것이에요.
예를 들어, totalPages가 3이라면 [1, 2, 3] 같은 배열을 만들고 싶은 거죠.2. 배열 생성 방법
자바스크립트에서 배열을 생성할 때는 여러 가지 방법이 있어요.
그 중 하나가 **Array.from()**을 사용하는 방법이에요.
- **Array.from()**은 배열을 만들 때 매우 유용한 함수에요. 두 가지 주요 역할을 해요:
- 길이를 정해서 배열을 만들기
- 배열을 만들면서, 각 요소를 어떻게 채울지 정의하기
3. 첫 번째 인자: 길이 설정
Array.from({ length: totalPages });
위 코드는 길이가 totalPages만큼인 배열을 만들어요.
예를 들어 totalPages가 3이라면 길이가 3인 배열이 만들어지는데,
기본적으로 요소는 undefined로 채워져요.4. 두 번째 인자: 배열을 어떻게 채울지
Array.from()의 두 번째 인자로, 배열의 각 요소를 어떻게 만들지 정의할 수 있어요.
이 인자는 함수 형태로 들어가는데,
각 요소의 index 값을 이용해 우리가 원하는 값으로 채울 수 있어요.(_, index) => index + 1
- **index**는 배열의 각 요소가 몇 번째인지 나타내는 값이에요.
0부터 시작해서 배열 길이만큼 순차적으로 증가해요.- 우리는 배열을 1부터 시작하는 숫자 배열로 만들고 싶으니 index + 1을 사용해요.
예를 들어, index가 0이면 1이 되고, index가 1이면 2가 되는 식으로요.
5. 전체 코드 이해
Array.from({ length: totalPages }, (_, index) => index + 1);
이 코드는 길이가 totalPages인 배열을 만들고,
그 배열의 각 요소에 1, 2, 3,... 순으로 숫자를 채우는 코드에요.
첫 번째 인자: { length: totalPages } → 배열의 길이를 설정.
두 번째 인자: (_, index) => index + 1 → 배열의 각 요소에 1부터 차례로 숫자를 채움.
6. 대체 방법: for문을 사용하는 방법
이 코드가 조금 생소하다면, 전통적인 for문을 사용해서 배열을 만들 수도 있어요.
let pages = []; for (let i = 1; i <= totalPages; i++) { pages.push(i); } console.log(pages); // [1, 2, 3, ...]
이 방법은 for문으로 1부터 totalPages까지의 숫자를 차례대로 배열에 추가하는 방식이죠.
Array.from() 보다는 익숙할 수 있지만,
배열을 다루는 자바스크립트의 최신 문법이 익숙해지면 더 효율적으로 작업할 수 있어요!
인자의 정의 >
**인자(Argument)**는 함수를 호출할 때 함수에 전달하는 값을 말해요.
함수에 어떤 값을 넣어서 호출하면, 그 값이 인자가 되는 거죠.
예를 들어, 아래와 같은 함수가 있다고 해볼게요:
sayHello("Alice")에서 "Alice"가 인자예요.함수를 호출할 때 전달하는 값이죠.function sayHello(name) { console.log("Hello, " + name); } sayHello("Alice");
이 값은 함수 안에서 name이라는 매개변수로 받아서 사용돼요.
Array.from()에서의 인자
Array.from() 같은 함수도 인자를 받는데요, Array.from()은 두 개의 인자를 받을 수 있어요:
첫 번째 인자는 배열로 변환할 대상이에요.
우리 코드에서는 { length: totalPages }가 첫 번째 인자죠.
이 객체는 길이가 totalPages인 배열을 만들기 위한 용도로 사용돼요.
두 번째 인자는 배열의 각 요소를 변환하는 함수예요.
(_, index) => index + 1가 두 번째 인자죠.
이건 콜백 함수로,
배열의 각 요소의 인덱스를 받아서 원하는 값으로 변환해요.
여기서는 인덱스에 1을 더해 1, 2, 3... 이런 식의 배열을 만드는 거예요.
따라서 첫 번째 인자는 배열을 만들고,
두 번째 인자는 그 배열의 값을 어떻게 변환할지 결정하는 거예요.
다시 정리하자면:
인자(Argument): 함수에 전달하는 값.
Array.from({ length: totalPages }, (_, index) => index + 1)에서:
첫 번째 인자: { length: totalPages }는 배열의 길이를 지정.
두 번째 인자: (_, index) => index + 1는 배열의 요소를 변환하는 함수.
인수랑 인자랑 차이 >
**인자(Argument)**와 **인수(Argument)**는 사실 같은 개념이에요.
두 용어 모두 함수에 전달하는 값을 의미하고, 상황에 따라 다르게 표현될 뿐이에요.
**"인자"**는 주로 프로그래밍 용어로 많이 사용돼요.**"인수"**는 수학적 배경에서 주로 쓰이는 말이에요.
두 단어는 같은 것을 가리키므로, 프로그래밍에서 인자라고 부르든 인수라고 부르든 차이는 없어요.
그냥 다른 표현일 뿐, 의미는 동일하게 함수에 넘겨주는 값을 말해요.
예를 들어, 함수 sayHello("Alice")에서 "Alice"는:
**인자(Argument)**라고도 부르고,**인수(Argument)**라고도 부를 수 있어요.
둘 다 맞는 표현이니, 헷갈릴 필요는 없어요!
2. (_, index): 배열의 인덱스 활용
(_, index)는 두 개의 인수를 받아요. 여기서 첫 번째 인수 _는 배열의 값인데, 값을 쓰지 않기 때문에 무시하는 거고,
두 번째 인수 index는 **각 배열 요소의 위치(인덱스)**를 의미해요. 그래서 각 페이지 번호를 index로 활용하는 거예요.
- index는 0부터 시작하니까 페이지 번호는 index + 1로 계산하게 돼요.
(_, index) => (
<li key={index}>
{/* 페이지 번호는 index + 1 */}
</li>
)
3. <li>와 <a> 태그 생성
이제 페이지 번호를 표시하기 위해서 <li>와 <a> 태그를 배열의 각 항목에 대해 생성해요.
각 항목은 페이지 번호에 해당하죠.
- index가 0이면, 1번 페이지를 나타내고,
- index가 1이면, 2번 페이지를 나타내고,
- 이런 식으로 계속되죠.
<ol>
{Array.from({ length: totalPages }, (_, index) => (
<li key={index}> {/* 각 페이지 번호 */}
<a href="#">{index + 1}</a> {/* 1, 2, 3 등 페이지 번호 */}
</li>
))}
</ol>
4. className을 통해 현재 페이지 표시
여기서 className={currentPage === index + 1 ? "active" : ""}는 현재 페이지와 비교해서 현재 페이지일 경우 "active" 클래스를 추가해요.
- 예를 들어, currentPage가 2라면 2번 페이지에 "active" 클래스가 붙고, 나머지 페이지는 빈 문자열이 들어가서 아무 스타일도 적용되지 않아요.
className={currentPage === index + 1 ? "active" : ""}
// currentPage가 2이면 index + 1 = 2에 "active" 클래스가 붙음
5. onClick 이벤트: 페이지 이동 처리
이제 onClick 이벤트로 페이지 번호를 클릭했을 때, 새 페이지로 이동하게 만들어요. 여기서 event.preventDefault()는 페이지 새로고침을 막는 역할을 하고, onPageChange(index + 1)를 호출해서 해당 페이지로 이동하게 돼요.
- index + 1은 페이지 번호니까, 1번 페이지, 2번 페이지로 이동하도록 호출하는 거예요.
onClick={(event) => {
event.preventDefault(); // 페이지 새로고침 막기
onPageChange(index + 1); // 클릭한 페이지로 이동
}}
전체적으로 보면...
이 코드는 totalPages 만큼 페이지 번호를 만든 뒤, 클릭할 때마다 해당 페이지로 이동하게 하는 로직이에요.
- 배열을 만든다: Array.from({ length: totalPages })
- 각 페이지 번호를 <li>와 <a>로 표시: index + 1
- 현재 페이지에 active 클래스 추가
- 페이지 번호를 클릭하면 이동: onPageChange(index + 1)
이렇게 작동하는 거예요!
다음 페이지 버튼
<a
href="#"
onClick={handleNextClick}
className={currentPage === totalPages ? "disabled" : ""}
>
<FontAwesomeIcon icon={faAngleRight} />
</a>
- "다음 페이지" 버튼도 이전 버튼과 비슷하게 동작합니다.
- 현재 페이지가 마지막 페이지일 경우 disabled 클래스를 추가하여 비활성화합니다.
- 클릭 시 handleNextClick 함수가 실행되어 다음 페이지로 이동합니다.
최종 구조
- "이전 페이지" 버튼을 눌렀을 때, 이전 페이지로 이동.
- 페이지 번호를 클릭하면 해당 페이지로 이동.
- "다음 페이지" 버튼을 눌렀을 때, 다음 페이지로 이동.
- 현재 페이지는 강조(active 클래스)되고, 이전/다음 버튼은 첫 페이지 또는 마지막 페이지에서 비활성화됩니다.
더 직관적으로 정리
- currentPage: 지금 보고 있는 페이지.
- totalPages: 전체 페이지 수.
- onPageChange: 페이지가 바뀌면 부모에게 새로운 페이지 번호를 알려주는 함수.
- 페이지 이동은 이전/다음 버튼이나 페이지 번호를 클릭하면 일어나고,
- 페이지가 바뀌면 부모 컴포넌트가 알아서 currentPage를 변경해서 UI가 업데이트됩니다.
'> IT 노트 > 활용' 카테고리의 다른 글
[리액트] 페이지 함수 만들기 (5) | 2024.09.08 |
---|---|
[리액트] Font Awesome 라이브러리 사용하기 (0) | 2024.09.07 |
[CSS] Font Awesome 같은 아이콘 라이브러리 사용 방법 (1) | 2024.09.06 |
[CSS] 스크롤 바 꾸미기 (0) | 2024.08.20 |
[CSS] aisde 2개 페이지 만들기 (0) | 2024.07.30 |