react-table/src/plugin-hooks/useGlobalFilter.js
Jason Clark 512f615988
Add disableGlobalFilter prop to allow for columns (and instance) to ignore global filter (#1963)
* size-snapshot created?

* Added `disableGlobalFilter` prop and associated tests

* Updated documentation

* improvement(useglobalfilter): add `disableGlobalFilter` prop

Adding `disableGlobalFilter` prop to both table and column to allow columns to be excluded from
Global Filter

* test(usefilters.test.js): added base test for disableGlobalFilter

Needed a test to make sure that disableGlobalFilter didn't break anything when applied

* Delete .size-snapshot.json

* Update README.md

Co-authored-by: Jason Clark <jason.clark@tcnbroadcasting.com>
Co-authored-by: Tanner Linsley <tannerlinsley@gmail.com>
2020-03-06 15:49:00 -07:00

181 lines
4.3 KiB
JavaScript

import React from 'react'
import {
getFilterMethod,
shouldAutoRemoveFilter,
getFirstDefined,
} from '../utils'
import {
actions,
useMountedLayoutEffect,
functionalUpdate,
useGetLatest,
} from '../publicUtils'
import * as filterTypes from '../filterTypes'
// Actions
actions.resetGlobalFilter = 'resetGlobalFilter'
actions.setGlobalFilter = 'setGlobalFilter'
export const useGlobalFilter = hooks => {
hooks.stateReducers.push(reducer)
hooks.useInstance.push(useInstance)
}
useGlobalFilter.pluginName = 'useGlobalFilter'
function reducer(state, action, previousState, instance) {
if (action.type === actions.resetGlobalFilter) {
return {
...state,
globalFilter: instance.initialState.globalFilter || undefined,
}
}
if (action.type === actions.setGlobalFilter) {
const { filterValue } = action
const { userFilterTypes } = instance
const filterMethod = getFilterMethod(
instance.globalFilter,
userFilterTypes || {},
filterTypes
)
const newFilter = functionalUpdate(filterValue, state.globalFilter)
//
if (shouldAutoRemoveFilter(filterMethod.autoRemove, newFilter)) {
const { globalFilter, ...stateWithoutGlobalFilter } = state
return stateWithoutGlobalFilter
}
return {
...state,
globalFilter: newFilter,
}
}
}
function useInstance(instance) {
const {
data,
rows,
flatRows,
rowsById,
allColumns,
filterTypes: userFilterTypes,
globalFilter,
manualGlobalFilter,
state: { globalFilter: globalFilterValue },
dispatch,
autoResetGlobalFilter = true,
disableGlobalFilter,
} = instance
const setGlobalFilter = React.useCallback(
filterValue => {
dispatch({ type: actions.setGlobalFilter, filterValue })
},
[dispatch]
)
// TODO: Create a filter cache for incremental high speed multi-filtering
// This gets pretty complicated pretty fast, since you have to maintain a
// cache for each row group (top-level rows, and each row's recursive subrows)
// This would make multi-filtering a lot faster though. Too far?
const [
globalFilteredRows,
globalFilteredFlatRows,
globalFilteredRowsById,
] = React.useMemo(() => {
if (manualGlobalFilter || typeof globalFilterValue === 'undefined') {
return [rows, flatRows, rowsById]
}
const filteredFlatRows = []
const filteredRowsById = {}
const filterMethod = getFilterMethod(
globalFilter,
userFilterTypes || {},
filterTypes
)
if (!filterMethod) {
console.warn(`Could not find a valid 'globalFilter' option.`)
return rows
}
allColumns.forEach(column => {
const { disableGlobalFilter: columnDisableGlobalFilter } = column
column.canFilter = getFirstDefined(
columnDisableGlobalFilter === true ? false : undefined,
disableGlobalFilter === true ? false : undefined,
true
)
})
const filterableColumns = allColumns.filter(c => c.canFilter === true)
// Filters top level and nested rows
const filterRows = filteredRows => {
filteredRows = filterMethod(
filteredRows,
filterableColumns.map(d => d.id),
globalFilterValue
)
filteredRows.forEach(row => {
filteredFlatRows.push(row)
filteredRowsById[row.id] = row
row.subRows =
row.subRows && row.subRows.length
? filterRows(row.subRows)
: row.subRows
})
return filteredRows
}
return [filterRows(rows), filteredFlatRows, filteredRowsById]
}, [
manualGlobalFilter,
globalFilterValue,
globalFilter,
userFilterTypes,
allColumns,
rows,
flatRows,
rowsById,
disableGlobalFilter,
])
const getAutoResetGlobalFilter = useGetLatest(autoResetGlobalFilter)
useMountedLayoutEffect(() => {
if (getAutoResetGlobalFilter()) {
dispatch({ type: actions.resetGlobalFilter })
}
}, [dispatch, manualGlobalFilter ? null : data])
Object.assign(instance, {
preGlobalFilteredRows: rows,
preGlobalFilteredFlatRows: flatRows,
preGlobalFilteredRowsById: rowsById,
globalFilteredRows,
globalFilteredFlatRows,
globalFilteredRowsById,
rows: globalFilteredRows,
flatRows: globalFilteredFlatRows,
rowsById: globalFilteredRowsById,
setGlobalFilter,
disableGlobalFilter,
})
}