React에서 페이지 번호부여를 구현하는 방법
저는 ReactJs에 익숙하지 않고 간단한 TODO 어플리케이션을 만들고 있습니다.실제로 DB 연결이 없는 매우 기본적인 앱으로 작업이 배열에 저장됩니다.편집 및 삭제 기능을 추가했습니다.페이지 매김을 추가하겠습니다.
어떻게 구현해야 합니까?어떤 도움이라도 주시면 감사하겠습니다.감사합니다.!!
최근 Pure React JS에서 페이지네이션(pagnation)을 구현했습니다.여기 작업 데모가 있습니다.http://codepen.io/PiotrBerebecki/pen/pEYPbY
물론 로직과 페이지 번호가 표시되는 방법을 조정하여 요건을 충족시켜야 합니다.
풀코드:
class TodoApp extends React.Component {
constructor() {
super();
this.state = {
todos: ['a','b','c','d','e','f','g','h','i','j','k'],
currentPage: 1,
todosPerPage: 3
};
this.handleClick = this.handleClick.bind(this);
}
handleClick(event) {
this.setState({
currentPage: Number(event.target.id)
});
}
render() {
const { todos, currentPage, todosPerPage } = this.state;
// Logic for displaying todos
const indexOfLastTodo = currentPage * todosPerPage;
const indexOfFirstTodo = indexOfLastTodo - todosPerPage;
const currentTodos = todos.slice(indexOfFirstTodo, indexOfLastTodo);
const renderTodos = currentTodos.map((todo, index) => {
return <li key={index}>{todo}</li>;
});
// Logic for displaying page numbers
const pageNumbers = [];
for (let i = 1; i <= Math.ceil(todos.length / todosPerPage); i++) {
pageNumbers.push(i);
}
const renderPageNumbers = pageNumbers.map(number => {
return (
<li
key={number}
id={number}
onClick={this.handleClick}
>
{number}
</li>
);
});
return (
<div>
<ul>
{renderTodos}
</ul>
<ul id="page-numbers">
{renderPageNumbers}
</ul>
</div>
);
}
}
ReactDOM.render(
<TodoApp />,
document.getElementById('app')
);
나는 piotr-berebecki가 준 간단한 페이지 매김 예를 재현하려고 노력했는데, 그것은 훌륭했다.그러나 페이지가 많을 경우 페이지 수가 화면에 넘치게 됩니다.그래서 앞, 뒤 버튼과 함께 앞, 뒤 버튼을 사용하여 페이지를 앞뒤로 스트리밍했습니다.그리고 디자인 부분에서는 부트스트랩 3을 사용했습니다.
페이지 바인딩 값을 사용하여 페이지 번호에 표시할 페이지 수를 사용자 정의할 수 있습니다.upperPageBound 및 pageBound에 동일한 값을 사용해야 합니다.
class TodoApp extends React.Component {
constructor() {
super();
this.state = {
todos: ['a','b','c','d','e','f','g','h','i','j','k','l','m',
'n','o','p','q','r','s','t','u','v','w','x','y','z'],
currentPage: 1,
todosPerPage: 3,
upperPageBound: 3,
lowerPageBound: 0,
isPrevBtnActive: 'disabled',
isNextBtnActive: '',
pageBound: 3
};
this.handleClick = this.handleClick.bind(this);
this.btnDecrementClick = this.btnDecrementClick.bind(this);
this.btnIncrementClick = this.btnIncrementClick.bind(this);
this.btnNextClick = this.btnNextClick.bind(this);
this.btnPrevClick = this.btnPrevClick.bind(this);
// this.componentDidMount = this.componentDidMount.bind(this);
this.setPrevAndNextBtnClass = this.setPrevAndNextBtnClass.bind(this);
}
componentDidUpdate() {
$("ul li.active").removeClass('active');
$('ul li#'+this.state.currentPage).addClass('active');
}
handleClick(event) {
let listid = Number(event.target.id);
this.setState({
currentPage: listid
});
$("ul li.active").removeClass('active');
$('ul li#'+listid).addClass('active');
this.setPrevAndNextBtnClass(listid);
}
setPrevAndNextBtnClass(listid) {
let totalPage = Math.ceil(this.state.todos.length / this.state.todosPerPage);
this.setState({isNextBtnActive: 'disabled'});
this.setState({isPrevBtnActive: 'disabled'});
if(totalPage === listid && totalPage > 1){
this.setState({isPrevBtnActive: ''});
}
else if(listid === 1 && totalPage > 1){
this.setState({isNextBtnActive: ''});
}
else if(totalPage > 1){
this.setState({isNextBtnActive: ''});
this.setState({isPrevBtnActive: ''});
}
}
btnIncrementClick() {
this.setState({upperPageBound: this.state.upperPageBound + this.state.pageBound});
this.setState({lowerPageBound: this.state.lowerPageBound + this.state.pageBound});
let listid = this.state.upperPageBound + 1;
this.setState({ currentPage: listid});
this.setPrevAndNextBtnClass(listid);
}
btnDecrementClick() {
this.setState({upperPageBound: this.state.upperPageBound - this.state.pageBound});
this.setState({lowerPageBound: this.state.lowerPageBound - this.state.pageBound});
let listid = this.state.upperPageBound - this.state.pageBound;
this.setState({ currentPage: listid});
this.setPrevAndNextBtnClass(listid);
}
btnPrevClick() {
if((this.state.currentPage -1)%this.state.pageBound === 0 ){
this.setState({upperPageBound: this.state.upperPageBound - this.state.pageBound});
this.setState({lowerPageBound: this.state.lowerPageBound - this.state.pageBound});
}
let listid = this.state.currentPage - 1;
this.setState({ currentPage : listid});
this.setPrevAndNextBtnClass(listid);
}
btnNextClick() {
if((this.state.currentPage +1) > this.state.upperPageBound ){
this.setState({upperPageBound: this.state.upperPageBound + this.state.pageBound});
this.setState({lowerPageBound: this.state.lowerPageBound + this.state.pageBound});
}
let listid = this.state.currentPage + 1;
this.setState({ currentPage : listid});
this.setPrevAndNextBtnClass(listid);
}
render() {
const { todos, currentPage, todosPerPage,upperPageBound,lowerPageBound,isPrevBtnActive,isNextBtnActive } = this.state;
// Logic for displaying current todos
const indexOfLastTodo = currentPage * todosPerPage;
const indexOfFirstTodo = indexOfLastTodo - todosPerPage;
const currentTodos = todos.slice(indexOfFirstTodo, indexOfLastTodo);
const renderTodos = currentTodos.map((todo, index) => {
return <li key={index}>{todo}</li>;
});
// Logic for displaying page numbers
const pageNumbers = [];
for (let i = 1; i <= Math.ceil(todos.length / todosPerPage); i++) {
pageNumbers.push(i);
}
const renderPageNumbers = pageNumbers.map(number => {
if(number === 1 && currentPage === 1){
return(
<li key={number} className='active' id={number}><a href='#' id={number} onClick={this.handleClick}>{number}</a></li>
)
}
else if((number < upperPageBound + 1) && number > lowerPageBound){
return(
<li key={number} id={number}><a href='#' id={number} onClick={this.handleClick}>{number}</a></li>
)
}
});
let pageIncrementBtn = null;
if(pageNumbers.length > upperPageBound){
pageIncrementBtn = <li className=''><a href='#' onClick={this.btnIncrementClick}> … </a></li>
}
let pageDecrementBtn = null;
if(lowerPageBound >= 1){
pageDecrementBtn = <li className=''><a href='#' onClick={this.btnDecrementClick}> … </a></li>
}
let renderPrevBtn = null;
if(isPrevBtnActive === 'disabled') {
renderPrevBtn = <li className={isPrevBtnActive}><span id="btnPrev"> Prev </span></li>
}
else{
renderPrevBtn = <li className={isPrevBtnActive}><a href='#' id="btnPrev" onClick={this.btnPrevClick}> Prev </a></li>
}
let renderNextBtn = null;
if(isNextBtnActive === 'disabled') {
renderNextBtn = <li className={isNextBtnActive}><span id="btnNext"> Next </span></li>
}
else{
renderNextBtn = <li className={isNextBtnActive}><a href='#' id="btnNext" onClick={this.btnNextClick}> Next </a></li>
}
return (
<div>
<ul>
{renderTodos}
</ul>
<ul id="page-numbers" className="pagination">
{renderPrevBtn}
{pageDecrementBtn}
{renderPageNumbers}
{pageIncrementBtn}
{renderNextBtn}
</ul>
</div>
);
}
}
ReactDOM.render(
<TodoApp />,
document.getElementById('app')
);
작업 데모 링크: https://codepen.io/mhmanandhar/pen/oEWBqx
react-bootstrap lib에서 커스텀 페이지화 컴포넌트를 작성하는 방법 및 이 컴포넌트를 프로젝트 전체에서 사용할 수 있습니다.
페이지 구성 요소(pagination.jsx 또는 js)
import React, { Component } from "react";
import { Pagination } from "react-bootstrap";
import PropTypes from "prop-types";
export default class PaginationHandler extends Component {
constructor(props) {
super(props);
this.state = {
paging: {
offset: 0,
limit: 10
},
active: 0
};
}
pagingHandler = () => {
let offset = parseInt(event.target.id);
this.setState({
active: offset
});
this.props.pageHandler(event.target.id - 1); };
nextHandler = () => {
let active = this.state.active;
this.setState({
active: active + 1
});
this.props.pageHandler(active + 1); };
backHandler = () => {
let active = this.state.active;
this.setState({
active: active - 1
});
this.props.pageHandler(active - 1); };
renderPageNumbers = (pageNumbers, totalPages) => {
let { active } = this.state;
return (
<Pagination>
<Pagination.Prev disabled={active < 5} onClick={ active >5 && this.backHandler} />
{
pageNumbers.map(number => {
if (
number >= parseInt(active) - 3 &&
number <= parseInt(active) + 3
) {
return (
<Pagination.Item
id={number}
active={number == active}
onClick={this.pagingHandler}
>
{number}
</Pagination.Item>
);
} else {
return null;
}
})}
<Pagination.Next onClick={ active <= totalPages -4 && this.nextHandler} />
</Pagination>
); };
buildComponent = (props, state) => {
const { totalPages } = props;
const pageNumbers = [];
for (let i = 1; i <= totalPages; i++) {
pageNumbers.push(i);
}
return (
<div className="pull-right">
{this.renderPageNumbers(pageNumbers ,totalPages)}
</div>
);
};
render() {
return this.buildComponent(this.props, this.state);
}
}
PaginationHandler.propTypes =
{
paging: PropTypes.object,
pageHandler: PropTypes.func,
totalPages: PropTypes.object
};
아래 그림과 같이 부모 컴포넌트에서 위의 자녀 컴포넌트 사용
import Pagination from "../pagination";
pageHandler = (offset) =>{
this.setState(({ paging }) => ({
paging: { ...paging, offset: offset }
}));
}
render() {
return (
<div>
<Pagination
paging = {paging}
pageHandler = {this.pageHandler}
totalPages = {totalPages}>
</Pagination>
</div>
);
}
Sample pagination react js working code
import React, { Component } from 'react';
import {
Pagination,
PaginationItem,
PaginationLink
} from "reactstrap";
let prev = 0;
let next = 0;
let last = 0;
let first = 0;
export default class SamplePagination extends Component {
constructor() {
super();
this.state = {
todos: ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','T','v','u','w','x','y','z'],
currentPage: 1,
todosPerPage: 3,
};
this.handleClick = this.handleClick.bind(this);
this.handleLastClick = this.handleLastClick.bind(this);
this.handleFirstClick = this.handleFirstClick.bind(this);
}
handleClick(event) {
event.preventDefault();
this.setState({
currentPage: Number(event.target.id)
});
}
handleLastClick(event) {
event.preventDefault();
this.setState({
currentPage:last
});
}
handleFirstClick(event) {
event.preventDefault();
this.setState({
currentPage:1
});
}
render() {
let { todos, currentPage, todosPerPage } = this.state;
// Logic for displaying current todos
let indexOfLastTodo = currentPage * todosPerPage;
let indexOfFirstTodo = indexOfLastTodo - todosPerPage;
let currentTodos = todos.slice(indexOfFirstTodo, indexOfLastTodo);
prev = currentPage > 0 ? (currentPage -1) :0;
last = Math.ceil(todos.length/todosPerPage);
next = (last === currentPage) ?currentPage: currentPage +1;
// Logic for displaying page numbers
let pageNumbers = [];
for (let i = 1; i <=last; i++) {
pageNumbers.push(i);
}
return (
<div>
<ul>
{
currentTodos.map((todo,index) =>{
return <li key={index}>{todo}</li>;
})
}
</ul><ul id="page-numbers">
<nav>
<Pagination>
<PaginationItem>
{ prev === 0 ? <PaginationLink disabled>First</PaginationLink> :
<PaginationLink onClick={this.handleFirstClick} id={prev} href={prev}>First</PaginationLink>
}
</PaginationItem>
<PaginationItem>
{ prev === 0 ? <PaginationLink disabled>Prev</PaginationLink> :
<PaginationLink onClick={this.handleClick} id={prev} href={prev}>Prev</PaginationLink>
}
</PaginationItem>
{
pageNumbers.map((number,i) =>
<Pagination key= {i}>
<PaginationItem active = {pageNumbers[currentPage-1] === (number) ? true : false} >
<PaginationLink onClick={this.handleClick} href={number} key={number} id={number}>
{number}
</PaginationLink>
</PaginationItem>
</Pagination>
)}
<PaginationItem>
{
currentPage === last ? <PaginationLink disabled>Next</PaginationLink> :
<PaginationLink onClick={this.handleClick} id={pageNumbers[currentPage]} href={pageNumbers[currentPage]}>Next</PaginationLink>
}
</PaginationItem>
<PaginationItem>
{
currentPage === last ? <PaginationLink disabled>Last</PaginationLink> :
<PaginationLink onClick={this.handleLastClick} id={pageNumbers[currentPage]} href={pageNumbers[currentPage]}>Last</PaginationLink>
}
</PaginationItem>
</Pagination>
</nav>
</ul>
</div>
);
}
}
ReactDOM.render(
<SamplePagination />,
document.getElementById('root')
);
최근 Google 검색 결과와 같은 페이징 로직을 구현하는 페이지화 구성 요소를 만들었습니다.
import React, { PropTypes } from 'react';
const propTypes = {
items: PropTypes.array.isRequired,
onChangePage: PropTypes.func.isRequired,
initialPage: PropTypes.number
}
const defaultProps = {
initialPage: 1
}
class Pagination extends React.Component {
constructor(props) {
super(props);
this.state = { pager: {} };
}
componentWillMount() {
this.setPage(this.props.initialPage);
}
setPage(page) {
var items = this.props.items;
var pager = this.state.pager;
if (page < 1 || page > pager.totalPages) {
return;
}
// get new pager object for specified page
pager = this.getPager(items.length, page);
// get new page of items from items array
var pageOfItems = items.slice(pager.startIndex, pager.endIndex + 1);
// update state
this.setState({ pager: pager });
// call change page function in parent component
this.props.onChangePage(pageOfItems);
}
getPager(totalItems, currentPage, pageSize) {
// default to first page
currentPage = currentPage || 1;
// default page size is 10
pageSize = pageSize || 10;
// calculate total pages
var totalPages = Math.ceil(totalItems / pageSize);
var startPage, endPage;
if (totalPages <= 10) {
// less than 10 total pages so show all
startPage = 1;
endPage = totalPages;
} else {
// more than 10 total pages so calculate start and end pages
if (currentPage <= 6) {
startPage = 1;
endPage = 10;
} else if (currentPage + 4 >= totalPages) {
startPage = totalPages - 9;
endPage = totalPages;
} else {
startPage = currentPage - 5;
endPage = currentPage + 4;
}
}
// calculate start and end item indexes
var startIndex = (currentPage - 1) * pageSize;
var endIndex = Math.min(startIndex + pageSize - 1, totalItems - 1);
// create an array of pages to ng-repeat in the pager control
var pages = _.range(startPage, endPage + 1);
// return object with all pager properties required by the view
return {
totalItems: totalItems,
currentPage: currentPage,
pageSize: pageSize,
totalPages: totalPages,
startPage: startPage,
endPage: endPage,
startIndex: startIndex,
endIndex: endIndex,
pages: pages
};
}
render() {
var pager = this.state.pager;
return (
<ul className="pagination">
<li className={pager.currentPage === 1 ? 'disabled' : ''}>
<a onClick={() => this.setPage(1)}>First</a>
</li>
<li className={pager.currentPage === 1 ? 'disabled' : ''}>
<a onClick={() => this.setPage(pager.currentPage - 1)}>Previous</a>
</li>
{pager.pages.map((page, index) =>
<li key={index} className={pager.currentPage === page ? 'active' : ''}>
<a onClick={() => this.setPage(page)}>{page}</a>
</li>
)}
<li className={pager.currentPage === pager.totalPages ? 'disabled' : ''}>
<a onClick={() => this.setPage(pager.currentPage + 1)}>Next</a>
</li>
<li className={pager.currentPage === pager.totalPages ? 'disabled' : ''}>
<a onClick={() => this.setPage(pager.totalPages)}>Last</a>
</li>
</ul>
);
}
}
Pagination.propTypes = propTypes;
Pagination.defaultProps
export default Pagination;
페이지 구성 요소를 사용하여 150개의 예제 항목 목록에 페이지를 지정하는 예제 App 구성 요소는 다음과 같습니다.
import React from 'react';
import Pagination from './Pagination';
class App extends React.Component {
constructor() {
super();
// an example array of items to be paged
var exampleItems = _.range(1, 151).map(i => { return { id: i, name: 'Item ' + i }; });
this.state = {
exampleItems: exampleItems,
pageOfItems: []
};
// bind function in constructor instead of render (https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md)
this.onChangePage = this.onChangePage.bind(this);
}
onChangePage(pageOfItems) {
// update state with new page of items
this.setState({ pageOfItems: pageOfItems });
}
render() {
return (
<div>
<div className="container">
<div className="text-center">
<h1>React - Pagination Example with logic like Google</h1>
{this.state.pageOfItems.map(item =>
<div key={item.id}>{item.name}</div>
)}
<Pagination items={this.state.exampleItems} onChangePage={this.onChangePage} />
</div>
</div>
<hr />
<div className="credits text-center">
<p>
<a href="http://jasonwatmore.com" target="_top">JasonWatmore.com</a>
</p>
</div>
</div>
);
}
}
export default App;
자세한 내용과 라이브 데모는 이 게시물을 참조하십시오.
코드 앤 박스에 있는 이 코드 샘플을 참조하십시오.
https://codesandbox.io/s/pagino-13pit
import Pagino from "pagino";
import { useState, useMemo } from "react";
export default function App() {
const [pages, setPages] = useState([]);
const pagino = useMemo(() => {
const _ = new Pagino({
showFirst: false,
showLast: false,
onChange: (page, count) => setPages(_.getPages())
});
_.setCount(10);
return _;
}, []);
const hanglePaginoNavigation = (type) => {
if (typeof type === "string") {
pagino[type]?.();
return;
}
pagino.setPage(type);
};
return (
<div>
<h1>Page: {pagino.page}</h1>
<ul>
{pages.map((page) => (
<button key={page} onClick={() => hanglePaginoNavigation(page)}>
{page}
</button>
))}
</ul>
</div>
);
}
- 사용1 - 사용react-bootstrap
import React from "react";
import { Pagination } from "react-bootstrap";
import Link from "next/link";
interface PaginateProps {
pages: number;
page: number;
keyword?: string;
isAdmin?: boolean;
}
const Paginate = ({
pages,
page,
// keyword is for searching
keyword = "",
isAdmin = false,
}: PaginateProps) => {
return pages > 1 ? (
<Pagination>
{/* keys returns a new Array iterator contians the keys for each index */}
// pages is total number of pages
{[...Array(pages).keys()].map((x) => (
// this is next.js component. you could use react Link
<Link
passHref
key={x + 1}
href={
!isAdmin
// since array indexing starts at 0, use x+1
? `/?keyword=${keyword}&page=${x + 1}`
: `/admin/productlist/?keyword=${keyword}&page=${x + 1}`
}
>
<Pagination.Item active={x + 1 === page}>{x + 1}</Pagination.Item>
</Link>
))}
</Pagination>
) : null;
};
export default Paginate;
페이지에서 사용합니다.
<Paginate page={page} pages={pages} keyword={keyword} />
2-반응-반응-유도 페이지화 사용
import Pagination from "react-js-pagination";
// bootstrap class to center
<div className="d-flex justify-content-center mt-5">
<Pagination
activePage={page}
itemsCountPerPage={resPerPageValue}
totalItemsCount={Count}
onChange={handlePagination}
nextPageText={"Next"}
prevPageText={"Prev"}
firstPageText={"First"}
lastPageText={"Last"}
// overwriting the style
itemClass="page-item"
linkClass="page-link"
/>
</div>
onChange 핸들러
const handlePagination = (pageNumber) => {
// window.location.href will reload entire page
router.push(`/?page=${pageNumber}`);
};
저는 최근에 다음과 같은 페이지 번호 부여 사례에 대처하는 데 도움이 되는 라이브러리를 만들었습니다.
- 정규화된 데이터 저장, Redx에
- 검색 필터 기반 페이지 캐시
- 단순화된 리액트 가상화 목록 사용
- 백그라운드에서 결과 새로 고침
- 마지막으로 방문한 페이지 및 사용된 필터 저장
DEMO 페이지는 위의 모든 기능을 구현합니다.
Github에서 찾을 수 있는 소스 코드
페이지 매김을 렌더링하는 ReactJS 덤 컴포넌트.이 라이브러리를 사용할 수도 있습니다.
https://www.npmjs.com/package/react-js-pagination
다음은 예를 제시하겠습니다.
http://vayser.github.io/react-js-pagination/
또는
이 https://codepen.io/PiotrBerebecki/pen/pEYPbY도 이용하실 수 있습니다.
Tabler-React를 사용한 다른 컴포넌트로 만들어야 합니다.
import * as React from "react";
import { Page, Button } from "tabler-react";
class PaginateComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
limit: 5, // optional
page: 1
};
}
paginateValue = (page) => {
this.setState({ page: page });
console.log(page) // access this value from parent component
}
paginatePrevValue = (page) => {
this.setState({ page: page });
console.log(page) // access this value from parent component
}
paginateNxtValue = (page) => {
this.setState({ page: page });
console.log(page) // access this value from parent component
}
render() {
return (
<div>
<div>
<Button.List>
<Button
disabled={this.state.page === 0}
onClick={() => this.paginatePrevValue(this.state.page - 1)}
outline
color="primary"
>
Previous
</Button>
{this.state.array.map((value, index) => {
return (
<Button
onClick={() => this.paginateValue(value)}
color={
this.state.page === value
? "primary"
: "secondary"
}
>
{value}
</Button>
);
})}
<Button
onClick={() => this.paginateNxtValue(this.state.page + 1)}
outline
color="secondary"
>
Next
</Button>
</Button.List>
</div>
</div>
)
}
}
export default PaginateComponent;
ReactJs에서 페이지 번호 매기기 + 검색을 구현했습니다. 출력: Pagination in React를 참조하십시오.
GitHub에서 완전한 코드를 표시: https://github.com/navanathjadhav/generic-pagination
또, 페이지 번호의 단계적인 실장에 대해서는, 다음의 문서를 참조해 주세요.https://everblogs.com/react/3-simple-steps-to-add-pagination-in-react/
페이지화 컴포넌트를 드리겠습니다.신입생에게는 조금 이해하기 어려울 수도 있습니다.react
:
https://www.npmjs.com/package/pagination
언급URL : https://stackoverflow.com/questions/40232847/how-to-implement-pagination-in-react
'programing' 카테고리의 다른 글
ng-repeat 내의 명령어와 스코프 '@'의 불가사의한 힘 사용 (0) | 2023.02.15 |
---|---|
워드프레스 next_post_link/previous_post_link가 동일한 범주에 속하지 않습니다. (0) | 2023.02.15 |
ESLint 기본 내보내기 Import/prefer-default-export 선호 (0) | 2023.02.15 |
JSON 만드는 법NET String Enum Converter는 하이픈 구분 대소문자를 사용합니다. (0) | 2023.02.15 |
사용자 이름과 비밀번호를 사용하여 MongoDB를 보호하는 방법 (0) | 2023.02.15 |