Skip to content

Commit

Permalink
feat(usePagination): support return sliced list directly (pass list
Browse files Browse the repository at this point in the history
… in options), add `indexStart`, `indexEnd` in returns
  • Loading branch information
vikiboss committed Aug 14, 2024
1 parent 3d793da commit 2ed32ff
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 5 deletions.
12 changes: 11 additions & 1 deletion src/use-pagination/demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import { Button, Card, KeyValue, LabelInput, Zone } from '@/components'
import { useControlledComponent, usePagination } from '@shined/react-use'

const TOTAL = 100
const DATA = Array.from({ length: TOTAL }, (_, i) => i + 1)

export function App() {
const pageSizeInput = useControlledComponent('20')
const targetPageInput = useControlledComponent('1')

const [state, actions] = usePagination({ pageSize: +pageSizeInput.value, total: TOTAL })
const [state, actions] = usePagination({ list: DATA, pageSize: +pageSizeInput.value, total: TOTAL })

return (
<Card>
Expand All @@ -19,6 +20,15 @@ export function App() {
<KeyValue label="Current page" value={state.currentPage} />
<KeyValue label="Page count" value={state.pageCount} />
</Zone>
<Zone border="primary">
{state.list.map((item) => {
return (
<div className="text-amber-5/80 font-bold" key={item}>
{item}
</div>
)
})}
</Zone>
<Zone>
<Button onClick={actions.prev} disabled={state.isFirstPage}>
Prev
Expand Down
35 changes: 31 additions & 4 deletions src/use-pagination/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { useMemo } from 'react'
import { useClamp } from '../use-clamp'
import { useCreation } from '../use-creation'
import { useLatest } from '../use-latest'
import { useStableFn } from '../use-stable-fn'
import { useUpdateEffect } from '../use-update-effect'

export interface UsePaginationOptions {
export interface UsePaginationOptions<T> {
/**
* Total number of items.
*
Expand All @@ -23,6 +24,10 @@ export interface UsePaginationOptions {
* @defaultValue 1
*/
page?: number
/**
* The original list to be paginated.
*/
list?: T[]
/**
* Callback when the `page` change.
*
Expand All @@ -46,7 +51,7 @@ export interface UsePaginationOptions {
onPageCountChange?: (pagination: UsePaginationReturnsState) => void
}

export interface UsePaginationReturnsState {
export interface UsePaginationReturnsState<T = any> {
/**
* Total number of items.
*/
Expand All @@ -63,6 +68,14 @@ export interface UsePaginationReturnsState {
* The total number of pages.
*/
pageCount: number
/**
* The start index of the displayed list (helpful to slice the list).
*/
indexStart: number
/**
* The end index of the displayed list (helpful to slice the list).
*/
indexEnd: number
/**
* Whether the current page is the first page.
*/
Expand All @@ -71,6 +84,10 @@ export interface UsePaginationReturnsState {
* Whether the current page is the last page.
*/
isLastPage: boolean
/**
* The sliced list to display.
*/
list: T[]
}

export interface UsePaginationReturnsActions {
Expand Down Expand Up @@ -102,12 +119,12 @@ export interface UsePaginationReturnsActions {
setPageSize: (size: number) => void
}

export type UsePaginationReturns = readonly [UsePaginationReturnsState, UsePaginationReturnsActions]
export type UsePaginationReturns<T> = readonly [UsePaginationReturnsState<T>, UsePaginationReturnsActions]

/**
* A React Hook that manage pagination state.
*/
export function usePagination(options: UsePaginationOptions = {}): UsePaginationReturns {
export function usePagination<T = any>(options: UsePaginationOptions<T> = {}): UsePaginationReturns<T> {
const {
total = Number.POSITIVE_INFINITY,
page = 1,
Expand All @@ -127,13 +144,23 @@ export function usePagination(options: UsePaginationOptions = {}): UsePagination
const next = useStableFn(() => pageActions.inc())
const setPageSize = useStableFn((size: number) => sizeActions.set(size))

const [indexStart, indexEnd] = [(currentPage - 1) * currentPageSize, Math.min(currentPage * currentPageSize, total)]

const slicedList = useMemo(
() => (options.list ?? []).slice(indexStart, indexEnd),
[options.list, indexStart, indexEnd],
)

const pagination = {
total,
currentPage,
currentPageSize,
pageCount,
indexStart,
indexEnd,
isFirstPage: currentPage === 1,
isLastPage: isInfinity ? false : currentPage === pageCount,
list: slicedList,
}

const latest = useLatest({ pagination, onPageChange, onPageCountChange, onPageSizeChange })
Expand Down

0 comments on commit 2ed32ff

Please sign in to comment.