fix(use-pagination): better controlled/manual use-pagination
21
README.md
@ -182,15 +182,18 @@ import {
|
||||
|
||||
# Examples
|
||||
|
||||
- [Basic - Client Side](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/basic-client-side)
|
||||
- [Sorting - Client Side](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/sorting-client-side)
|
||||
- [Filtering - Client Side](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/filtering-client-side)
|
||||
- [Grouping - Client Side](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/grouping-client-side)
|
||||
- [Pagination - Client Side](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/pagination-client-side)
|
||||
- [Row Selection - Client Side](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/row-selection-client-side)
|
||||
- [Expanding - Client Side](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/expanding-client-side)
|
||||
- [Sub Components](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/sub-components)
|
||||
- [Editable Data](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/editable-cells)
|
||||
- Simple
|
||||
- [Basic](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/basic)
|
||||
- [Sorting](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/sorting)
|
||||
- [Filtering](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/filtering)
|
||||
- [Grouping](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/grouping)
|
||||
- [Pagination](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/pagination)
|
||||
- [Row Selection](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/row-selection)
|
||||
- [Expanding](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/expanding)
|
||||
- [Sub Components](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/sub-components)
|
||||
- [Editable Data](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/editable-cells)
|
||||
- Controlled
|
||||
- [Pagination (Controlled)](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/pagination-controlled)
|
||||
|
||||
# Concepts
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
276
examples/pagination-controlled/src/App.js
Normal file
@ -0,0 +1,276 @@
|
||||
import React from 'react'
|
||||
import styled from 'styled-components'
|
||||
import { useTable, useTableState, usePagination } from 'react-table'
|
||||
|
||||
import makeData from './makeData'
|
||||
|
||||
const Styles = styled.div`
|
||||
padding: 1rem;
|
||||
|
||||
table {
|
||||
border-spacing: 0;
|
||||
border: 1px solid black;
|
||||
|
||||
tr {
|
||||
:last-child {
|
||||
td {
|
||||
border-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
margin: 0;
|
||||
padding: 0.5rem;
|
||||
border-bottom: 1px solid black;
|
||||
border-right: 1px solid black;
|
||||
|
||||
:last-child {
|
||||
border-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pagination {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
`
|
||||
|
||||
// Let's add a fetchData method to our Table component that will be used to fetch
|
||||
// new data when pagination state changes
|
||||
// We can also add a loading state to let our table know it's loading new data
|
||||
function Table({
|
||||
columns,
|
||||
data,
|
||||
fetchData,
|
||||
loading,
|
||||
pageCount: controlledPageCount,
|
||||
}) {
|
||||
// Use useTableState to hoist the state (and state updater) out of the table and control it
|
||||
const tableState = useTableState({ pageIndex: 0 })
|
||||
|
||||
// Now we can get our table state from the hoisted table state tuple
|
||||
const [{ pageIndex, pageSize }] = tableState
|
||||
|
||||
// Listen for changes in pagination and use the state to fetch our new data
|
||||
React.useEffect(
|
||||
() => {
|
||||
fetchData({ pageIndex, pageSize })
|
||||
},
|
||||
[fetchData, pageIndex, pageSize]
|
||||
)
|
||||
|
||||
const {
|
||||
getTableProps,
|
||||
headerGroups,
|
||||
prepareRow,
|
||||
page,
|
||||
canPreviousPage,
|
||||
canNextPage,
|
||||
pageOptions,
|
||||
pageCount,
|
||||
gotoPage,
|
||||
nextPage,
|
||||
previousPage,
|
||||
setPageSize,
|
||||
} = useTable(
|
||||
{
|
||||
columns,
|
||||
data,
|
||||
state: tableState, // Pass our hoisted table state
|
||||
manualPagination: true, // Tell the usePagination
|
||||
// hook that we'll handle our own data fetching
|
||||
// This means we'll also have to provide our own
|
||||
// pageCount.
|
||||
pageCount: controlledPageCount,
|
||||
},
|
||||
usePagination
|
||||
)
|
||||
|
||||
// Render the UI for your table
|
||||
return (
|
||||
<>
|
||||
<pre>
|
||||
<code>
|
||||
{JSON.stringify(
|
||||
{
|
||||
pageIndex,
|
||||
pageSize,
|
||||
pageCount,
|
||||
canNextPage,
|
||||
canPreviousPage,
|
||||
},
|
||||
null,
|
||||
2
|
||||
)}
|
||||
</code>
|
||||
</pre>
|
||||
<table {...getTableProps()}>
|
||||
<thead>
|
||||
{headerGroups.map(headerGroup => (
|
||||
<tr {...headerGroup.getHeaderGroupProps()}>
|
||||
{headerGroup.headers.map(column => (
|
||||
<th {...column.getHeaderProps()}>{column.render('Header')}</th>
|
||||
))}
|
||||
</tr>
|
||||
))}
|
||||
</thead>
|
||||
<tbody>
|
||||
{page.map(
|
||||
(row, i) =>
|
||||
prepareRow(row) || (
|
||||
<tr {...row.getRowProps()}>
|
||||
{row.cells.map(cell => {
|
||||
return (
|
||||
<td {...cell.getCellProps()}>{cell.render('Cell')}</td>
|
||||
)
|
||||
})}
|
||||
</tr>
|
||||
)
|
||||
)}
|
||||
{loading ? (
|
||||
// Use our custom loading state to show a loading indicator
|
||||
<tr>
|
||||
<td>Loading...</td>
|
||||
</tr>
|
||||
) : null}
|
||||
</tbody>
|
||||
</table>
|
||||
{/*
|
||||
Pagination can be built however you'd like.
|
||||
This is just a very basic UI implementation:
|
||||
*/}
|
||||
<div className="pagination">
|
||||
<button onClick={() => gotoPage(0)} disabled={!canPreviousPage}>
|
||||
{'<<'}
|
||||
</button>{' '}
|
||||
<button onClick={() => previousPage()} disabled={!canPreviousPage}>
|
||||
{'<'}
|
||||
</button>{' '}
|
||||
<button onClick={() => nextPage()} disabled={!canNextPage}>
|
||||
{'>'}
|
||||
</button>{' '}
|
||||
<button onClick={() => gotoPage(pageCount - 1)} disabled={!canNextPage}>
|
||||
{'>>'}
|
||||
</button>{' '}
|
||||
<span>
|
||||
Page{' '}
|
||||
<strong>
|
||||
{pageIndex + 1} of {pageOptions.length}
|
||||
</strong>{' '}
|
||||
</span>
|
||||
<span>
|
||||
| Go to page:{' '}
|
||||
<input
|
||||
type="number"
|
||||
defaultValue={pageIndex + 1}
|
||||
onChange={e => {
|
||||
const page = e.target.value ? Number(e.target.value) - 1 : 0
|
||||
gotoPage(page)
|
||||
}}
|
||||
style={{ width: '100px' }}
|
||||
/>
|
||||
</span>{' '}
|
||||
<select
|
||||
value={pageSize}
|
||||
onChange={e => {
|
||||
setPageSize(Number(e.target.value))
|
||||
}}
|
||||
>
|
||||
{[10, 20, 30, 40, 50].map(pageSize => (
|
||||
<option key={pageSize} value={pageSize}>
|
||||
Show {pageSize}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
// Let's simulate a large dataset on the server (outside of our component)
|
||||
const serverData = makeData(10000)
|
||||
|
||||
function App() {
|
||||
const columns = React.useMemo(
|
||||
() => [
|
||||
{
|
||||
Header: 'Name',
|
||||
columns: [
|
||||
{
|
||||
Header: 'First Name',
|
||||
accessor: 'firstName',
|
||||
},
|
||||
{
|
||||
Header: 'Last Name',
|
||||
accessor: 'lastName',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
Header: 'Info',
|
||||
columns: [
|
||||
{
|
||||
Header: 'Age',
|
||||
accessor: 'age',
|
||||
},
|
||||
{
|
||||
Header: 'Visits',
|
||||
accessor: 'visits',
|
||||
},
|
||||
{
|
||||
Header: 'Status',
|
||||
accessor: 'status',
|
||||
},
|
||||
{
|
||||
Header: 'Profile Progress',
|
||||
accessor: 'progress',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
[]
|
||||
)
|
||||
|
||||
// We'll start our table without any data
|
||||
const [data, setData] = React.useState([])
|
||||
const [loading, setLoading] = React.useState(false)
|
||||
const [pageCount, setPageCount] = React.useState(0)
|
||||
|
||||
const fetchData = React.useCallback(({ pageSize, pageIndex }) => {
|
||||
// This will get called when the table needs new data
|
||||
// You could fetch your data from literally anywhere,
|
||||
// even a server. But for this example, we'll just fake it.
|
||||
|
||||
// Set the loading state
|
||||
setLoading(true)
|
||||
|
||||
// We'll even set a delay to simulate a server here
|
||||
setTimeout(() => {
|
||||
const startRow = pageSize * pageIndex
|
||||
const endRow = startRow + pageSize
|
||||
setData(serverData.slice(startRow, endRow))
|
||||
|
||||
// Your server could send back total page count.
|
||||
// For now we'll just fake it, too
|
||||
setPageCount(Math.ceil(serverData.length / pageSize))
|
||||
|
||||
setLoading(false)
|
||||
}, 1000)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Styles>
|
||||
<Table
|
||||
columns={columns}
|
||||
data={data}
|
||||
fetchData={fetchData}
|
||||
loading={loading}
|
||||
pageCount={pageCount}
|
||||
/>
|
||||
</Styles>
|
||||
)
|
||||
}
|
||||
|
||||
export default App
|
||||
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
3
examples/pagination/sandbox.config.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"infiniteLoopProtection": false
|
||||
}
|
||||