mirror of
https://github.com/gosticks/react-table.git
synced 2026-08-11 20:40:17 +00:00
Add sorting guide
This commit is contained in:
@@ -505,6 +505,79 @@ function MyTable({ columns, data }) {
|
||||
}
|
||||
```
|
||||
|
||||
## `useSortBy`
|
||||
|
||||
- Plugin Hook
|
||||
- Optional
|
||||
|
||||
`useSortBy` is the hook that implements **row sorting**. It also support multi-sort (keyboard required).
|
||||
|
||||
### Table Options
|
||||
|
||||
The following options are supported via the main options object passed to `useTable(options)`
|
||||
|
||||
- `state[0].sortBy: Array<Object<id: columnID, desc: Bool>>`
|
||||
- Must be **memoized**
|
||||
- An array of sorting objects. If there is more than one object in the array, multi-sorting will be enabled. Each sorting object should contain an `id` key with the corresponding column ID to sort by. An optional `desc` key may be set to true or false to indicated ascending or descending sorting for that column. This information is stored in state since the table is allowed to manipulate the filter through user interaction.
|
||||
- `manualSorting: Bool`
|
||||
- Enables sorting detection functionality, but does not automatically perform row sorting. Turn this on if you wish to implement your own sorting outside of the table (eg. server-side or manual row grouping/nesting)
|
||||
- `disableSorting: Bool`
|
||||
- Disables sorting for every column in the entire table.
|
||||
- `disableMultiSort: Bool`
|
||||
- Disables multi-sorting for the entire table.
|
||||
- `disableSortRemove: Bool`
|
||||
- If true, the un-sorted state will not be available to columns once they have been sorted.
|
||||
- `disableMultiRemove: Bool`
|
||||
- If true, the un-sorted state will not be available to multi-sorted columns.
|
||||
- `orderByFn: Function`
|
||||
- Must be **memoizd**
|
||||
- Defaults to the built-in [default orderBy function](TODO)
|
||||
- This function is responsible for composing multiple sorting functions together for multi-sorting, and also handles both the directional sorting and stable-sorting tie breaking. Rarely would you want to override this function unless you have a very advanced use-case that requires it.
|
||||
- `sortTypes: Object<sortKey: sortType>`
|
||||
- Must be **memoized**
|
||||
- Allows overriding or adding additional sort types for columns to use. If a column's sort type isn't found on this object, it will default to using the [built-in sort types](TODO).
|
||||
- For mor information on sort types, see [Sorting](TODO)
|
||||
|
||||
### `Column` Options
|
||||
|
||||
- `sortDescFirst: Bool`
|
||||
- Optional
|
||||
- Defaults to `false`
|
||||
- If true, the first sort direction for this column will be descending instead of ascending
|
||||
- `sortInverted: Bool`
|
||||
- Optional
|
||||
- Defaults to `false`
|
||||
- If true, the underlying sorting direction will be inverted, but the UI will not.
|
||||
- This may be useful in situations where positive and negative connotation is inverted, eg. a Golfing score where a lower score is considered more positive than a higher one.
|
||||
- `sortType: String | Function`
|
||||
- If a **function** is passed, it must be **memoized**
|
||||
- Defaults to [`alphanumeric`](TODO)
|
||||
- The resolved function from the this string/function will be used to sort the this column's data.
|
||||
- If a `string` is passed, the function with that name located on either the custom `sortTypes` option or the built-in sorting types object will be used. If
|
||||
- If a `function` is passed, it will be used.
|
||||
- For mor information on sort types, see [Sorting](TODO)
|
||||
|
||||
### Instance Variables
|
||||
|
||||
The following values are provided to the table `instance`:
|
||||
|
||||
- `rows: Array<Row>`
|
||||
- An array of **sorted** rows.
|
||||
|
||||
### Example
|
||||
|
||||
```js
|
||||
const state = useTableState({ sortBy: [{ id: 'firstName', desc: true }] })
|
||||
|
||||
const { rows } = useTable(
|
||||
{
|
||||
// state[0].sortBy === [{ id: 'firstName', desc: true }]
|
||||
state,
|
||||
},
|
||||
useSortBy
|
||||
)
|
||||
```
|
||||
|
||||
## `useGroupBy`
|
||||
|
||||
- Plugin Hook
|
||||
@@ -650,69 +723,6 @@ const { rows } = useTable(
|
||||
)
|
||||
```
|
||||
|
||||
## `useSortBy`
|
||||
|
||||
- Plugin Hook
|
||||
- Optional
|
||||
|
||||
`useSortBy` is the hook that implements **row sorting**. It also support multi-sort (keyboard required).
|
||||
|
||||
### Table Options
|
||||
|
||||
The following options are supported via the main options object passed to `useTable(options)`
|
||||
|
||||
- `state[0].sortBy: Array<Object<id: columnID, desc: Bool>>`
|
||||
- Must be **memoized**
|
||||
- An array of sorting objects. If there is more than one object in the array, multi-sorting will be enabled. Each sorting object should contain an `id` key with the corresponding column ID to sort by. An optional `desc` key may be set to true or false to indicated ascending or descending sorting for that column. This information is stored in state since the table is allowed to manipulate the filter through user interaction.
|
||||
- `defaultSortType: String | Function`
|
||||
- If a **function** is passed, it must be **memoized**
|
||||
- Defaults to [`alphanumeric`](TODO)
|
||||
- The function (or resolved function from the string) will be used as the default/fallback sort method for every column that has sorting enabled.
|
||||
- If a `string` is passed, the function with that name located on the `sortTypes` option object will be used.
|
||||
- If a `function` is passed, it will be used.
|
||||
- For mor information on sort types, see [Sorting](TODO)
|
||||
- `manualSorting: Bool`
|
||||
- Enables sorting detection functionality, but does not automatically perform row sorting. Turn this on if you wish to implement your own sorting outside of the table (eg. server-side or manual row grouping/nesting)
|
||||
- `disableSorting: Bool`
|
||||
- Disables sorting for every column in the entire table.
|
||||
- `disableMultiSort: Bool`
|
||||
- Disables multi-sorting for the entire table.
|
||||
- `defaultSortDesc: Bool`
|
||||
- If true, the first default direction for sorting will be descending. This may also be overridden at the column level.
|
||||
- `disableSortRemove: Bool`
|
||||
- If true, the un-sorted state will not be available to columns once they have been sorted.
|
||||
- `disableMultiRemove: Bool`
|
||||
- If true, the un-sorted state will not be available to multi-sorted columns.
|
||||
- `orderByFn: Function`
|
||||
- Must be **memoizd**
|
||||
- Defaults to the built-in [default orderBy function](TODO)
|
||||
- This function is responsible for composing multiple sorting functions together for multi-sorting, and also handles both the directional sorting and stable-sorting tie breaking. Rarely would you want to override this function unless you have a very advanced use-case that requires it.
|
||||
- `sortTypes: Object<sortKey: sortType>`
|
||||
- Must be **memoized**
|
||||
- Allows overriding or adding additional sort types for columns to use. If a column's sort type isn't found on this object, it will default to using the [built-in sort types](TODO).
|
||||
- For mor information on sort types, see [Sorting](TODO)
|
||||
|
||||
### Instance Variables
|
||||
|
||||
The following values are provided to the table `instance`:
|
||||
|
||||
- `rows: Array<Row>`
|
||||
- An array of **sorted** rows.
|
||||
|
||||
### Example
|
||||
|
||||
```js
|
||||
const state = useTableState({ sortBy: [{ id: 'firstName', desc: true }] })
|
||||
|
||||
const { rows } = useTable(
|
||||
{
|
||||
// state[0].sortBy === [{ id: 'firstName', desc: true }]
|
||||
state,
|
||||
},
|
||||
useSortBy
|
||||
)
|
||||
```
|
||||
|
||||
## `useExpanded`
|
||||
|
||||
- Plugin Hook
|
||||
@@ -933,7 +943,135 @@ export default function MyTable({ manualPageIndex }) {
|
||||
}
|
||||
```
|
||||
|
||||
<!-- # Guides
|
||||
# Guides
|
||||
|
||||
## Sorting
|
||||
|
||||
### Client-Side Sorting
|
||||
|
||||
Client-side sorting can be accomplished by using the `useSortBy` plugin hook. Start by importing the hook from `react-table`:
|
||||
|
||||
```diff
|
||||
-import { useTable } from 'react-table'
|
||||
+import { useTable, useSortBy } from 'react-table'
|
||||
```
|
||||
|
||||
Next, add the `useSortBy` hook to your `useTable` hook and add the necessary UI pieces we need to make sorting work:
|
||||
|
||||
```diff
|
||||
function MyTable() {
|
||||
const { getTableProps, headerGroups, rows, prepareRow } = useTable(
|
||||
{
|
||||
data,
|
||||
columns,
|
||||
},
|
||||
- useSortBy
|
||||
+ useSortBy
|
||||
)
|
||||
|
||||
return (
|
||||
<table {...getTableProps()}>
|
||||
<thead>
|
||||
{headerGroups.map(headerGroup => (
|
||||
<tr {...headerGroup.getHeaderGroupProps()}>
|
||||
{headerGroup.headers.map(column => (
|
||||
- <th {...column.getHeaderProps()}>
|
||||
+ <th {...column.getHeaderProps(column.getSortByToggleProps())}>
|
||||
{column.render('Header')}
|
||||
+ <span>
|
||||
+ {column.sorted ? (column.sortedDesc ? ' 🔽' : ' 🔼') : ''}
|
||||
+ </span>
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
))}
|
||||
</thead>
|
||||
<tbody>
|
||||
{rows.map(
|
||||
(row, i) =>
|
||||
prepareRow(row) || (
|
||||
<tr {...row.getRowProps()}>
|
||||
{row.cells.map(cell => {
|
||||
return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
|
||||
})}
|
||||
</tr>
|
||||
)
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### Server-Side Sorting
|
||||
|
||||
Server-side sorting can be accomplished by using the `useSortBy` plugin hook in **controlled** mode along with the `useTableState` hook. Start by importing these hooks from `react-table`:
|
||||
|
||||
```diff
|
||||
-import { useTable } from 'react-table'
|
||||
+import { useTable, useSortBy, useTableState } from 'react-table'
|
||||
```
|
||||
|
||||
Next, add the `useSortBy` and `useTableState` hooks to your `useTable` hook, configure the table state, then add the necessary UI pieces we need to make sorting work:
|
||||
|
||||
```diff
|
||||
function MyTable(data, columns, fetchData) {
|
||||
|
||||
+ const state = useTableState()
|
||||
+ const [{ sortBy }] = state
|
||||
|
||||
+ React.useEffect(() => {
|
||||
+ // When sorting changes, trigger your parent component
|
||||
+ // or hook to fetch new data with the table state
|
||||
+ fetchData(state[0])
|
||||
+ }, [sortBy])
|
||||
|
||||
const { getTableProps, headerGroups, rows, prepareRow } = useTable(
|
||||
{
|
||||
data,
|
||||
columns,
|
||||
+ state,
|
||||
+ manualSorting: true
|
||||
},
|
||||
- useSortBy
|
||||
+ useSortBy
|
||||
)
|
||||
|
||||
return (
|
||||
<table {...getTableProps()}>
|
||||
<thead>
|
||||
{headerGroups.map(headerGroup => (
|
||||
<tr {...headerGroup.getHeaderGroupProps()}>
|
||||
{headerGroup.headers.map(column => (
|
||||
- <th {...column.getHeaderProps()}>
|
||||
+ <th {...column.getHeaderProps(column.getSortByToggleProps())}>
|
||||
{column.render('Header')}
|
||||
+ <span>
|
||||
+ {column.sorted ? (column.sortedDesc ? ' 🔽' : ' 🔼') : ''}
|
||||
+ </span>
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
))}
|
||||
</thead>
|
||||
<tbody>
|
||||
{rows.map(
|
||||
(row, i) =>
|
||||
prepareRow(row) || (
|
||||
<tr {...row.getRowProps()}>
|
||||
{row.cells.map(cell => {
|
||||
return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
|
||||
})}
|
||||
</tr>
|
||||
)
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
<!--
|
||||
|
||||
## Client Side Pagination
|
||||
|
||||
|
||||
@@ -150,10 +150,8 @@ export const useFilters = props => {
|
||||
return filteredSoFar
|
||||
}
|
||||
|
||||
const columnFilter = column.filter || 'text'
|
||||
|
||||
const filterMethod = getFilterMethod(
|
||||
columnFilter,
|
||||
column.filter,
|
||||
userFilterTypes || {},
|
||||
filterTypes
|
||||
)
|
||||
|
||||
@@ -20,16 +20,14 @@ const propTypes = {
|
||||
// General
|
||||
columns: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
sortBy: PropTypes.func,
|
||||
defaultSortDesc: PropTypes.bool,
|
||||
sortType: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
||||
sortDescFirst: PropTypes.bool,
|
||||
})
|
||||
),
|
||||
orderByFn: PropTypes.func,
|
||||
sortTypes: PropTypes.object,
|
||||
defaultSortType: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
||||
manualSorting: PropTypes.bool,
|
||||
disableSorting: PropTypes.bool,
|
||||
defaultSortDesc: PropTypes.bool,
|
||||
disableMultiSort: PropTypes.bool,
|
||||
disableSortRemove: PropTypes.bool,
|
||||
disableMultiRemove: PropTypes.bool,
|
||||
@@ -43,11 +41,9 @@ export const useSortBy = props => {
|
||||
rows,
|
||||
columns,
|
||||
orderByFn = defaultOrderByFn,
|
||||
defaultSort = 'alphanumeric',
|
||||
sortTypes: userSortTypes,
|
||||
manualSorting,
|
||||
disableSorting,
|
||||
defaultSortDesc,
|
||||
disableSortRemove,
|
||||
disableMultiRemove,
|
||||
disableMultiSort,
|
||||
@@ -88,10 +84,7 @@ export const useSortBy = props => {
|
||||
|
||||
// Find the column for this columnID
|
||||
const column = columns.find(d => d.id === columnID)
|
||||
const resolvedDefaultSortDesc = getFirstDefined(
|
||||
column.defaultSortDesc,
|
||||
defaultSortDesc
|
||||
)
|
||||
const { sortDescFirst } = column
|
||||
|
||||
// Find any existing sortBy for this column
|
||||
const existingSortBy = sortBy.find(d => d.id === columnID)
|
||||
@@ -127,8 +120,8 @@ export const useSortBy = props => {
|
||||
!hasDescDefined && // Must not be setting desc
|
||||
(multi ? !disableMultiRemove : true) && // If multi, don't allow if disableMultiRemove
|
||||
((existingSortBy && // Finally, detect if it should indeed be removed
|
||||
(existingSortBy.desc && !resolvedDefaultSortDesc)) ||
|
||||
(!existingSortBy.desc && resolvedDefaultSortDesc))
|
||||
(existingSortBy.desc && !sortDescFirst)) ||
|
||||
(!existingSortBy.desc && sortDescFirst))
|
||||
) {
|
||||
action = 'remove'
|
||||
}
|
||||
@@ -137,7 +130,7 @@ export const useSortBy = props => {
|
||||
newSortBy = [
|
||||
{
|
||||
id: columnID,
|
||||
desc: hasDescDefined ? desc : resolvedDefaultSortDesc,
|
||||
desc: hasDescDefined ? desc : sortDescFirst,
|
||||
},
|
||||
]
|
||||
} else if (action === 'add') {
|
||||
@@ -145,7 +138,7 @@ export const useSortBy = props => {
|
||||
...sortBy,
|
||||
{
|
||||
id: columnID,
|
||||
desc: hasDescDefined ? desc : resolvedDefaultSortDesc,
|
||||
desc: hasDescDefined ? desc : sortDescFirst,
|
||||
},
|
||||
]
|
||||
} else if (action === 'toggle') {
|
||||
@@ -221,73 +214,68 @@ export const useSortBy = props => {
|
||||
column.sortedDesc = column.sorted ? column.sorted.desc : undefined
|
||||
})
|
||||
|
||||
const sortedRows = useMemo(() => {
|
||||
if (manualSorting || !sortBy.length) {
|
||||
return rows
|
||||
}
|
||||
if (debug) console.info('getSortedRows')
|
||||
const sortedRows = useMemo(
|
||||
() => {
|
||||
if (manualSorting || !sortBy.length) {
|
||||
return rows
|
||||
}
|
||||
if (debug) console.info('getSortedRows')
|
||||
|
||||
const sortTypesByColumnID = {}
|
||||
const sortData = rows => {
|
||||
// Use the orderByFn to compose multiple sortBy's together.
|
||||
// This will also perform a stable sorting using the row index
|
||||
// if needed.
|
||||
const sortedData = orderByFn(
|
||||
rows,
|
||||
sortBy.map(sort => {
|
||||
// Support custom sorting methods for each column
|
||||
const { sortType } = columns.find(d => d.id === sort.id)
|
||||
|
||||
columns.forEach(col => {
|
||||
sortTypesByColumnID[col.id] = col.sortBy
|
||||
})
|
||||
// Look up sortBy functions in this order:
|
||||
// column function
|
||||
// column string lookup on user sortType
|
||||
// column string lookup on built-in sortType
|
||||
// default function
|
||||
// default string lookup on user sortType
|
||||
// default string lookup on built-in sortType
|
||||
const sortMethod =
|
||||
isFunction(sortType) ||
|
||||
(userSortTypes || {})[sortType] ||
|
||||
sortTypes[sortType] ||
|
||||
sortTypes.alphanumeric
|
||||
|
||||
const sortData = rows => {
|
||||
// Use the orderByFn to compose multiple sortBy's together.
|
||||
// This will also perform a stable sorting using the row index
|
||||
// if needed.
|
||||
const sortedData = orderByFn(
|
||||
rows,
|
||||
sortBy.map(sort => {
|
||||
// Support custom sorting methods for each column
|
||||
const columnSort = sortTypesByColumnID[sort.id]
|
||||
// Return the correct sortFn
|
||||
return (a, b) =>
|
||||
sortMethod(a.values[sort.id], b.values[sort.id], sort.desc)
|
||||
}),
|
||||
// Map the directions
|
||||
sortBy.map(sort => {
|
||||
// Detect and use the sortInverted option
|
||||
const { sortInverted } = columns.find(d => d.id === sort.id)
|
||||
|
||||
// Look up sortBy functions in this order:
|
||||
// column function
|
||||
// column string lookup on user sortType
|
||||
// column string lookup on built-in sortType
|
||||
// default function
|
||||
// default string lookup on user sortType
|
||||
// default string lookup on built-in sortType
|
||||
const sortMethod =
|
||||
isFunction(columnSort) ||
|
||||
(userSortTypes || {})[columnSort] ||
|
||||
sortTypes[columnSort] ||
|
||||
isFunction(defaultSort) ||
|
||||
(userSortTypes || {})[defaultSort] ||
|
||||
sortTypes[defaultSort]
|
||||
if (sortInverted) {
|
||||
return sort.desc
|
||||
}
|
||||
|
||||
// Return the correct sortFn
|
||||
return (a, b) =>
|
||||
sortMethod(a.values[sort.id], b.values[sort.id], sort.desc)
|
||||
}),
|
||||
// Map the directions
|
||||
sortBy.map(d => !d.desc)
|
||||
)
|
||||
return !sort.desc
|
||||
})
|
||||
)
|
||||
|
||||
// If there are sub-rows, sort them
|
||||
sortedData.forEach(row => {
|
||||
if (!row.subRows) {
|
||||
return
|
||||
}
|
||||
row.subRows = sortData(row.subRows)
|
||||
})
|
||||
// If there are sub-rows, sort them
|
||||
sortedData.forEach(row => {
|
||||
if (!row.subRows) {
|
||||
return
|
||||
}
|
||||
row.subRows = sortData(row.subRows)
|
||||
})
|
||||
|
||||
return sortedData
|
||||
}
|
||||
return sortedData
|
||||
}
|
||||
|
||||
return sortData(rows)
|
||||
}, [
|
||||
manualSorting,
|
||||
sortBy,
|
||||
debug,
|
||||
columns,
|
||||
rows,
|
||||
orderByFn,
|
||||
userSortTypes,
|
||||
defaultSort,
|
||||
])
|
||||
return sortData(rows)
|
||||
},
|
||||
[manualSorting, sortBy, debug, columns, rows, orderByFn, userSortTypes]
|
||||
)
|
||||
|
||||
return {
|
||||
...props,
|
||||
|
||||
Reference in New Issue
Block a user