mirror of
https://github.com/gosticks/react-table.git
synced 2026-06-29 01:20:02 +00:00
Relocate columns and row logic, fix columns and useGroupBy to be more pure
Since useColumns was relying on groupBy logic, this was code smell. I wanted useGroupBy to be able to add that logic all by itself and not have to have dependencies in the core of the table. To fix that, I've moved the core column and row logic to the useTable hook and added a new hook 'columnsBeforeHeaderGroups' to allow useGroupBy to do what i needs in a more pure way.
This commit is contained in:
@@ -14,14 +14,11 @@ const propTypes = {
|
||||
// General
|
||||
columns: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
filterFn: PropTypes.func,
|
||||
filterAll: PropTypes.bool,
|
||||
canFilter: PropTypes.bool,
|
||||
disableFilters: PropTypes.bool,
|
||||
Filter: PropTypes.any,
|
||||
})
|
||||
),
|
||||
|
||||
filterFn: PropTypes.func,
|
||||
manualFilters: PropTypes.bool,
|
||||
}
|
||||
|
||||
@@ -99,12 +96,12 @@ export const useFilters = props => {
|
||||
|
||||
hooks.columns.push(columns => {
|
||||
columns.forEach(column => {
|
||||
const { id, accessor, canFilter } = column
|
||||
const { id, accessor, disableFilters: columnDisableFilters } = column
|
||||
|
||||
// Determine if a column is filterable
|
||||
column.canFilter = accessor
|
||||
? getFirstDefined(
|
||||
canFilter,
|
||||
columnDisableFilters,
|
||||
disableFilters === true ? false : undefined,
|
||||
true
|
||||
)
|
||||
@@ -143,13 +140,12 @@ export const useFilters = props => {
|
||||
// Find the filters column
|
||||
const column = columns.find(d => d.id === columnID)
|
||||
|
||||
column.preFilteredRows = filteredSoFar
|
||||
|
||||
// Don't filter hidden columns or columns that have had their filters disabled
|
||||
if (!column || column.filterable === false) {
|
||||
if (!column) {
|
||||
return filteredSoFar
|
||||
}
|
||||
|
||||
column.preFilteredRows = filteredSoFar
|
||||
|
||||
const filterMethod = getFilterMethod(
|
||||
column.filter,
|
||||
userFilterTypes || {},
|
||||
|
||||
@@ -20,12 +20,13 @@ const propTypes = {
|
||||
columns: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
aggregate: PropTypes.func,
|
||||
canGroupBy: PropTypes.bool,
|
||||
disableGrouping: PropTypes.bool,
|
||||
Aggregated: PropTypes.any,
|
||||
})
|
||||
),
|
||||
groupByFn: PropTypes.func,
|
||||
manualGrouping: PropTypes.bool,
|
||||
disableGrouping: PropTypes.bool,
|
||||
aggregations: PropTypes.object,
|
||||
}
|
||||
|
||||
@@ -44,13 +45,23 @@ export const useGroupBy = props => {
|
||||
state: [{ groupBy }, setState],
|
||||
} = props
|
||||
|
||||
// Sort grouped columns to the start of the column list
|
||||
// before the headers are built
|
||||
hooks.columnsBeforeHeaderGroups.push(columns => {
|
||||
return [
|
||||
...groupBy.map(g => columns.find(col => col.id === g)),
|
||||
...columns.filter(col => !groupBy.includes(col.id)),
|
||||
]
|
||||
})
|
||||
|
||||
columns.forEach(column => {
|
||||
const { id, accessor, canGroupBy } = column
|
||||
const { id, accessor, disableGrouping: columnDisableGrouping } = column
|
||||
column.grouped = groupBy.includes(id)
|
||||
column.groupedIndex = groupBy.indexOf(id)
|
||||
|
||||
column.canGroupBy = accessor
|
||||
? getFirstDefined(
|
||||
canGroupBy,
|
||||
columnDisableGrouping,
|
||||
disableGrouping === true ? false : undefined,
|
||||
true
|
||||
)
|
||||
@@ -115,81 +126,78 @@ export const useGroupBy = props => {
|
||||
hooks.columns.push(addGroupByToggleProps)
|
||||
hooks.headers.push(addGroupByToggleProps)
|
||||
|
||||
const groupedRows = useMemo(() => {
|
||||
if (manualGroupBy || !groupBy.length) {
|
||||
return rows
|
||||
}
|
||||
if (debug) console.info('getGroupedRows')
|
||||
// Find the columns that can or are aggregating
|
||||
|
||||
// Uses each column to aggregate rows into a single value
|
||||
const aggregateRowsToValues = rows => {
|
||||
const values = {}
|
||||
columns.forEach(column => {
|
||||
const columnValues = rows.map(d => d.values[column.id])
|
||||
let aggregate =
|
||||
userAggregations[column.aggregate] ||
|
||||
aggregations[column.aggregate] ||
|
||||
column.aggregate
|
||||
if (typeof aggregate === 'function') {
|
||||
values[column.id] = aggregate(columnValues, rows)
|
||||
} else if (aggregate) {
|
||||
throw new Error(
|
||||
`Invalid aggregate "${aggregate}" passed to column with ID: "${
|
||||
column.id
|
||||
}"`
|
||||
)
|
||||
} else {
|
||||
values[column.id] = columnValues[0]
|
||||
}
|
||||
})
|
||||
return values
|
||||
}
|
||||
|
||||
// Recursively group the data
|
||||
const groupRecursively = (rows, groupBy, depth = 0) => {
|
||||
// This is the last level, just return the rows
|
||||
if (depth >= groupBy.length) {
|
||||
const groupedRows = useMemo(
|
||||
() => {
|
||||
if (manualGroupBy || !groupBy.length) {
|
||||
return rows
|
||||
}
|
||||
if (debug) console.info('getGroupedRows')
|
||||
// Find the columns that can or are aggregating
|
||||
|
||||
// Group the rows together for this level
|
||||
let groupedRows = Object.entries(groupByFn(rows, groupBy[depth])).map(
|
||||
([groupByVal, subRows], index) => {
|
||||
// Recurse to sub rows before aggregation
|
||||
subRows = groupRecursively(subRows, groupBy, depth + 1)
|
||||
|
||||
const values = aggregateRowsToValues(subRows)
|
||||
|
||||
const row = {
|
||||
groupByID: groupBy[depth],
|
||||
groupByVal,
|
||||
values,
|
||||
subRows,
|
||||
depth,
|
||||
index,
|
||||
// Uses each column to aggregate rows into a single value
|
||||
const aggregateRowsToValues = rows => {
|
||||
const values = {}
|
||||
columns.forEach(column => {
|
||||
const columnValues = rows.map(d => d.values[column.id])
|
||||
let aggregate =
|
||||
userAggregations[column.aggregate] ||
|
||||
aggregations[column.aggregate] ||
|
||||
column.aggregate
|
||||
if (typeof aggregate === 'function') {
|
||||
values[column.id] = aggregate(columnValues, rows)
|
||||
} else if (aggregate) {
|
||||
throw new Error(
|
||||
`Invalid aggregate "${aggregate}" passed to column with ID: "${
|
||||
column.id
|
||||
}"`
|
||||
)
|
||||
} else {
|
||||
values[column.id] = columnValues[0]
|
||||
}
|
||||
return row
|
||||
})
|
||||
return values
|
||||
}
|
||||
|
||||
// Recursively group the data
|
||||
const groupRecursively = (rows, groupBy, depth = 0) => {
|
||||
// This is the last level, just return the rows
|
||||
if (depth >= groupBy.length) {
|
||||
return rows
|
||||
}
|
||||
)
|
||||
|
||||
return groupedRows
|
||||
}
|
||||
// Group the rows together for this level
|
||||
let groupedRows = Object.entries(groupByFn(rows, groupBy[depth])).map(
|
||||
([groupByVal, subRows], index) => {
|
||||
// Recurse to sub rows before aggregation
|
||||
subRows = groupRecursively(subRows, groupBy, depth + 1)
|
||||
|
||||
// Assign the new data
|
||||
return groupRecursively(rows, groupBy)
|
||||
}, [
|
||||
manualGroupBy,
|
||||
groupBy,
|
||||
debug,
|
||||
rows,
|
||||
columns,
|
||||
userAggregations,
|
||||
groupByFn,
|
||||
])
|
||||
const values = aggregateRowsToValues(subRows)
|
||||
|
||||
const row = {
|
||||
groupByID: groupBy[depth],
|
||||
groupByVal,
|
||||
values,
|
||||
subRows,
|
||||
depth,
|
||||
index,
|
||||
}
|
||||
return row
|
||||
}
|
||||
)
|
||||
|
||||
return groupedRows
|
||||
}
|
||||
|
||||
// Assign the new data
|
||||
return groupRecursively(rows, groupBy)
|
||||
},
|
||||
[manualGroupBy, groupBy, debug, rows, columns, userAggregations, groupByFn]
|
||||
)
|
||||
|
||||
return {
|
||||
...props,
|
||||
toggleGroupBy,
|
||||
rows: groupedRows,
|
||||
preGroupedRows: rows,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ const propTypes = {
|
||||
PropTypes.shape({
|
||||
sortType: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
||||
sortDescFirst: PropTypes.bool,
|
||||
disableSorting: PropTypes.bool,
|
||||
})
|
||||
),
|
||||
orderByFn: PropTypes.func,
|
||||
@@ -67,10 +68,10 @@ export const useSortBy = props => {
|
||||
}
|
||||
|
||||
columns.forEach(column => {
|
||||
const { accessor, canSortBy } = column
|
||||
const { accessor, disableSorting: columnDisableSorting } = column
|
||||
column.canSortBy = accessor
|
||||
? getFirstDefined(
|
||||
canSortBy,
|
||||
columnDisableSorting,
|
||||
disableSorting === true ? false : undefined,
|
||||
true
|
||||
)
|
||||
@@ -78,7 +79,7 @@ export const useSortBy = props => {
|
||||
})
|
||||
|
||||
// Updates sorting based on a columnID, desc flag and multi flag
|
||||
const toggleSortByID = (columnID, desc, multi) => {
|
||||
const toggleSortBy = (columnID, desc, multi) => {
|
||||
return setState(old => {
|
||||
const { sortBy } = old
|
||||
|
||||
@@ -167,7 +168,7 @@ export const useSortBy = props => {
|
||||
columns.forEach(column => {
|
||||
if (column.canSortBy) {
|
||||
column.toggleSortBy = (desc, multi) =>
|
||||
toggleSortByID(column.id, desc, multi)
|
||||
toggleSortBy(column.id, desc, multi)
|
||||
}
|
||||
})
|
||||
return columns
|
||||
@@ -279,6 +280,8 @@ export const useSortBy = props => {
|
||||
|
||||
return {
|
||||
...props,
|
||||
toggleSortBy,
|
||||
rows: sortedRows,
|
||||
preSortedRows: rows,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user