在你的 React 中构建此分页
我从 API 获取了一些数据,并希望对其进行分页。在本文中,我将使用 React 实现分页。
要求
假设 API 返回的是页面总值,我需要用这个值进行分页。同时,我还需要保留当前页面,以防用户跳转到其他页面。
这是要求:
流动
现在,我们有了一个简单的需求。在进行编码步骤之前,我先画出流程图。
在这个例子中,我认为我需要:
- 根据页面总值呈现所有页面。
pageIndex
指向当前页面的状态。
编码
首先,我们需要有一个 Next.js 项目。我们赶紧行动起来吧!
npx create-next-app@latest --typescript
步骤1:使用总页面值渲染所有页面。
仅用于演示,所以我将硬编码页面总值。我将其设置为 20。
import type {NextPage} from 'next'
import styles from '../styles/Home.module.css'
const PAGE_TOTAL = 20
const Home: NextPage = () => {
return (
<div className={styles.container}>
<ul className={styles.pagination}>
{Array.from({length: PAGE_TOTAL}, (_, idx) => (
<li className={styles.pageItem}>{idx + 1}</li>
))}
</ul>
</div>
)
}
export default Home
注意我如何呈现页面,并且页面编号仅使用Array.from
和idx + 1
。
步骤2:制作当前页面。
这一步我需要制作当前页面。
首先,在 React 中定义一个新的状态:
const [pageIndex, setPageIndex] = React.useState(0)
默认情况下,当前页为 0。
接下来,添加一个帮助我们更改当前页面的功能。
function handlePageChange(idx: number) {
setPageIndex(idx)
}
最后,添加当前页面的样式和onClick
事件。
<li
className={`${styles.pageItem} ${
idx === pageIndex ? styles.currentPage : ''
}`}
onClick={() => handlePageChange(idx)}
>
{idx + 1}
</li>
现在,我们可以更改当前页面。
到目前为止,我们几乎完成了分页。但假设我只想在屏幕上渲染 5 个页面,并且每当我点击另一个页面时,页面数就会自动增加。
我可以做到嗎?
是的,我们前进吧!
下一个要求
在本节中,我们将使分页更具交互性。我们需要在屏幕上渲染 5 个页面,其他页面会根据当前页面自动更改。
为了便于想象,请看下面的图片:
下一个流程
根据上述要求,为了实现新的分页,我需要为分页创建一个新的流程。
我们有三种情况:
- 总页面值小于5。
- 总页面价值大于5加上
pageIndex
价值。 - 总页面价值小于5加上
pageIndex
价值。
让我们更详细地分析一下上述这些案例!
总页面值小于5。
我把总页数设置为 20,这肯定不会发生。但在现实世界中,也许会发生。
这样的话,我们不需要再修改逻辑代码了,只需要保留之前需求中的代码即可。
总页面价值大于5加上pageIndex
价值。
每当我们点击新页面时,被点击的页面将移动到第一个位置,其余页面将自动呈现。
总页面价值小于5加上pageIndex
价值。
这种情况下,我们不能自动增加页面数,只能改变当前页面数的值。
下一步编码
我们需要对之前的代码进行三处修改:
- 页码。
- 总页数显示在屏幕上。
- 我们用来改变当前页面的函数。
- 当前页面逻辑。
总页面值小于5。
<li
className={`${styles.pageItem} ${
idx === pageIndex ? styles.currentPage : ''
}`}
onClick={() => handlePageChange(idx)}
>
{idx + 1}
</li>
总页面价值大于5加上pageIndex
价值。
在这种情况下,我们需要实现以下这些要求:
- 页码是当前页面索引加上我们点击的当前索引。
- 总页数:5。
- 当前页面索引始终为零。
{
Array.from({length: 5}, (_, idx) => (
<li
className={`${styles.pageItem} ${idx === 0 ? styles.currentPage : ''}`}
onClick={() => handlePageChange(pageIndex + idx)}
>
{pageIndex + idx + 1}
</li>
))
}
总页面价值小于5加上pageIndex
价值。
在这种情况下,我们需要实现以下这些要求:
- 从当前页面索引到总页面值计算出来的右侧页面数不等于5,所以需要取左侧剩余的页面数,起始索引就是左侧页面数中的第一个页面。
- 总页数:5。
- 当前页面索引始终为零。
const PAGE_TOTAL = 20
const Home: NextPage = () => {
const [pageIndex, setPageIndex] = React.useState(17)
function handlePageChange(idx: number) {
setPageIndex(idx)
}
// the right pages: 18,19,20
// the left pages: 16,17
// the start index: 15(page 16)
const numberOfRightPages = PAGE_TOTAL - pageIndex
const numberOfLeftPages = 5 - numberOfRightPages
const startPageIndex = pageIndex - numberOfLeftPages
return (
<div className={styles.container}>
<ul className={styles.pagination}>
{Array.from({length: 5}, (_, idx) => (
<li
key={`pagination-items-${idx}`}
className={`${styles.pageItem} ${
startPageIndex + idx === pageIndex ? styles.currentPage : ''
}`}
onClick={() => handlePageChange(startPageIndex + idx)}
>
{startPageIndex + idx + 1}
</li>
))}
</ul>
</div>
)
}
改进
我们有三种情况,考虑这些情况,有四种不同的逻辑。
- 页数。
- 当前页面检查。
- 页面索引。
- 总页数。
我们可以通过使用方法编写组件来改进我们的代码Inversion of Control
。
import type {NextPage} from 'next'
import styles from '../styles/Home.module.css'
import * as React from 'react'
const PAGE_TOTAL = 20
const NUMBER_PAGE = 5
function Pagination({
length,
isCurrentPage,
goToNewPage,
makeNumberPage,
}: {
length: number
isCurrentPage: (idx: number) => boolean
goToNewPage: (idx: number) => void
makeNumberPage: (idx: number) => number
}) {
return (
<ul className={styles.pagination}>
{Array.from({length}, (_, idx) => (
<li
className={`${styles.pageItem} ${
isCurrentPage(idx) ? styles.currentPage : ''
}`}
onClick={() => goToNewPage(idx)}
>
{makeNumberPage(idx)}
</li>
))}
</ul>
)
}
const Home: NextPage = () => {
const [pageIndex, setPageIndex] = React.useState(0)
function handlePageChange(idx: number) {
setPageIndex(idx)
}
if (PAGE_TOTAL < NUMBER_PAGE) {
return (
<Pagination
length={PAGE_TOTAL}
isCurrentPage={(idx) => idx === pageIndex}
goToNewPage={(idx) => handlePageChange(idx)}
makeNumberPage={(idx) => idx + 1}
/>
)
}
if (PAGE_TOTAL >= pageIndex + NUMBER_PAGE) {
return (
<Pagination
length={NUMBER_PAGE}
isCurrentPage={(idx) => idx === 0}
goToNewPage={(idx) => handlePageChange(pageIndex + idx)}
makeNumberPage={(idx) => pageIndex + idx + 1}
/>
)
}
if (PAGE_TOTAL < pageIndex + NUMBER_PAGE) {
// the right pages: 18,19,20
// the left pages: 16,17
// the start index: 15(page 16)
const numberOfRightPages = PAGE_TOTAL - pageIndex
const numberOfLeftPages = NUMBER_PAGE - numberOfRightPages
const startPageIndex = pageIndex - numberOfLeftPages
return (
<Pagination
length={NUMBER_PAGE}
isCurrentPage={(idx) => startPageIndex + idx === pageIndex}
goToNewPage={(idx) => handlePageChange(startPageIndex + idx)}
makeNumberPage={(idx) => startPageIndex + idx + 1}
/>
)
}
throw new Error(`Just avoid the error comes from typescript!`)
}
export default Home
我们有了新的分页!
您可以更改该NUMBER_PAGE
值,例如:我将其更改为 7。
结论
我们刚刚在 React 应用中创建了分页功能。在第一个示例中,一切看起来都很简单,但如果我们要为分页添加一些功能,则需要的代码量会比我们想象的要多。所以,为什么不想想你的分页方案,然后尝试一下呢?
文章来源:https://dev.to/thangphan37/build-this-pagination-in-your-react-5h8m