react-table
Version:
Hooks for building lightweight, fast and extendable datagrids for React
206 lines (173 loc) • 4.13 kB
JavaScript
import React from 'react'
//
import {
actions,
ensurePluginOrder,
functionalUpdate,
useMountedLayoutEffect,
useGetLatest,
} from '../publicUtils'
import { expandRows } from '../utils'
const pluginName = 'usePagination'
// Actions
actions.resetPage = 'resetPage'
actions.gotoPage = 'gotoPage'
actions.setPageSize = 'setPageSize'
export const usePagination = hooks => {
hooks.stateReducers.push(reducer)
hooks.useInstance.push(useInstance)
}
usePagination.pluginName = pluginName
function reducer(state, action, previousState, instance) {
if (action.type === actions.init) {
return {
pageSize: 10,
pageIndex: 0,
...state,
}
}
if (action.type === actions.resetPage) {
return {
...state,
pageIndex: instance.initialState.pageIndex || 0,
}
}
if (action.type === actions.gotoPage) {
const { pageCount, page } = instance
const newPageIndex = functionalUpdate(action.pageIndex, state.pageIndex)
let canNavigate = false
if (newPageIndex > state.pageIndex) {
// next page
canNavigate =
pageCount === -1
? page.length >= state.pageSize
: newPageIndex < pageCount
} else if (newPageIndex < state.pageIndex) {
// prev page
canNavigate = newPageIndex > -1
}
if (!canNavigate) {
return state
}
return {
...state,
pageIndex: newPageIndex,
}
}
if (action.type === actions.setPageSize) {
const { pageSize } = action
const topRowIndex = state.pageSize * state.pageIndex
const pageIndex = Math.floor(topRowIndex / pageSize)
return {
...state,
pageIndex,
pageSize,
}
}
}
function useInstance(instance) {
const {
rows,
autoResetPage = true,
manualExpandedKey = 'expanded',
plugins,
pageCount: userPageCount,
paginateExpandedRows = true,
expandSubRows = true,
state: {
pageSize,
pageIndex,
expanded,
globalFilter,
filters,
groupBy,
sortBy,
},
dispatch,
data,
manualPagination,
} = instance
ensurePluginOrder(
plugins,
['useGlobalFilter', 'useFilters', 'useGroupBy', 'useSortBy', 'useExpanded'],
'usePagination'
)
const getAutoResetPage = useGetLatest(autoResetPage)
useMountedLayoutEffect(() => {
if (getAutoResetPage()) {
dispatch({ type: actions.resetPage })
}
}, [
dispatch,
manualPagination ? null : data,
globalFilter,
filters,
groupBy,
sortBy,
])
const pageCount = manualPagination
? userPageCount
: Math.ceil(rows.length / pageSize)
const pageOptions = React.useMemo(
() =>
pageCount > 0
? [...new Array(pageCount)].fill(null).map((d, i) => i)
: [],
[pageCount]
)
const page = React.useMemo(() => {
let page
if (manualPagination) {
page = rows
} else {
const pageStart = pageSize * pageIndex
const pageEnd = pageStart + pageSize
page = rows.slice(pageStart, pageEnd)
}
if (paginateExpandedRows) {
return page
}
return expandRows(page, { manualExpandedKey, expanded, expandSubRows })
}, [
expandSubRows,
expanded,
manualExpandedKey,
manualPagination,
pageIndex,
pageSize,
paginateExpandedRows,
rows,
])
const canPreviousPage = pageIndex > 0
const canNextPage =
pageCount === -1 ? page.length >= pageSize : pageIndex < pageCount - 1
const gotoPage = React.useCallback(
pageIndex => {
dispatch({ type: actions.gotoPage, pageIndex })
},
[dispatch]
)
const previousPage = React.useCallback(() => {
return gotoPage(old => old - 1)
}, [gotoPage])
const nextPage = React.useCallback(() => {
return gotoPage(old => old + 1)
}, [gotoPage])
const setPageSize = React.useCallback(
pageSize => {
dispatch({ type: actions.setPageSize, pageSize })
},
[dispatch]
)
Object.assign(instance, {
pageOptions,
pageCount,
page,
canPreviousPage,
canNextPage,
gotoPage,
previousPage,
nextPage,
setPageSize,
})
}