React-Table: useFilter

useFilter

This example in the documentation was particularly confusing.

CodeSandbox: react-table/examples/filtering

It throws many filter types at you in one example, along with custom sorting algorithms, global filtering, while being generally poorly structured.

We can simplify this to two filter types, with no default filter, and one custom sort algorithm.

Edit react-table-usefilter-spi-forked

In this example our DataTable component has actually changed very little.

We have included the useFilters hook.

We have created two new memos

  • defaultColumn (required)
  • filterTypes (optional)

Of these two memos only one of them is required, which is defaultColumn, because that contains Filter, which is a column property that cannot be null now that we are rendering a filter div in our header blocks.

/components/DataTable.js
<div>{column.canFilter ? column.render("Filter") : null}</div>

In this example we donโ€™t want a default filter, so we simply passed an empty string to the Filter key.

/components/DataTable.js
const defaultColumn = React.useMemo(
    () => ({
      // Let's set up our default Filter UI
      Filter: ""
    }),
    []
  );

Filters in Utility File

There is no reason to keep the actual filter mini components themselves inside the DataTable component, cluttering everything up. So we have moved them to /utilities/filters.js where you can find the code for the TextSearchFilter and the DropdownFilter.

Those filters are then referenced in the columns prop object in PeopleDataTable

/components/PeopleDataTable.js
const columns = [
  {
    Header: "First Name",
    accessor: "firstName",
    Filter: TextSearchFilter,
    filter: "rankedMatchSorter"
  },
  {
    Header: "Last Name",
    accessor: "lastName",
    Filter: TextSearchFilter
  },
  {
    Header: "Age",
    accessor: "age"
  },
  {
    Header: "Visits",
    accessor: "visits"
  },
  {
    Header: "Status",
    accessor: "status",
    Filter: DropdownFilter
  },
  {
    Header: "Profile Progress",
    accessor: "progress"
  }
];

Note that we cannot use camelCase while naming these Filters because these are actually Components. Therefore they must start with Capitol letters.

Filter vs filter

Looking closely at this columns object we have two very similar keys. Filter and filter.

This was a particularly confusing bit of naming. The Filter key references the filtering component that we want to use (dropdown, slider, text input, date, whatever) and the filter key is actually referencing the list of custom sorting functions that we are allowed to include using the filterTypes memo.

/components/DataTable.js
const filterTypes = React.useMemo(
    () => ({
      rankedMatchSorter: matchSorterFn
    }),
    []
  );

Sorting Algorithms

For example here we have added the match-sorter library.

/utilities/sorting.js
// dependencies
import { matchSorter } from "match-sorter";

export function matchSorterFn(rows, id, filterValue) {
  return matchSorter(rows, filterValue, { keys: [(row) => row.values[id]] });
}

However you could add any number of custom sorting function here. For example if you wanted to include everything except the selection you could add an algorithm for that.

In the absence of a custom algorithm the filters use a simple exact match system.

The custom sorting algorithms are referenced in the filterTypes memo

/components/DataTable.js
import { matchSorterFn } from "../utilities/sorting";

const filterTypes = React.useMemo(
    () => ({
      rankedMatchSorter: matchSorterFn
    }),
    []
  );

and then referenced in the columns prop object

/components/PeopleDataTable.js
const columns = [
  {
    Header: "First Name",
    accessor: "firstName",
    Filter: TextSearchFilter,
    filter: "rankedMatchSorter"
  },
  // ...
];