DEV Community

Richard Beattie
Richard Beattie

Posted on • Originally published at r-bt.com

React Table useGlobalFilter with two columns

This week I needed to filter a table made with React Table. React table is great for its extensibility and so has hooks for this: useFilters and useGlobalFilter. useFilter is for filtering by an individual column and useGlobalFilter for filtering by content in any column.

However I needed to filter two columns by a single input. My table is for ingredients and has columns for: code, name, price per unit, supplier, etc. I need to filter by name and code. I couldn't use useFilters as that would do an intersection (i.e. the search query would need to be in both the code and name row).

See the end Code Sandbox at: https://codesandbox.io/s/fuzzy-text-global-filter-rcy1f?file=/src/Table.tsx

Filtering Ingredients on Prepsheets.com

Filtering Prepsheets.com Ingredients by Code

Thankfully, it's possible to do this with useGlobalFilter.

import { 
    ..., 
    useGlobalFilter,
} from 'react-table'

...

const {
    ...,
    setGlobalFilter,
} = useTable(
    {
        ...
    },
    ...
    useGlobalFilter,
);
Enter fullscreen mode Exit fullscreen mode

See Code Sandbox: https://codesandbox.io/s/all-columns-global-filter-buof9?file=/src/Table.tsx

Awesome, by using setGlobalFilter we can now filter by the content in any column. To restrict which columns we filter we'll specify a custom globalFilter function.

import {
    ...
    useGlobalFilter,
    Row, // Typescript
    IdType, // Typescript
}
import React, { ..., useCallback } = 'react'

...

const ourGlobalFilterFunction = useCallback(
    // This is Typescript if you're using JS remove the types (e.g. :string)
    (rows: Row<T>[], ids: IdType<T>[], query: string) => {
        return rows.filter((row) => 
            row.values['code'].includes(query) ||
            row.values['name'].includes(query)
        );
    },
    [],
);

const {
    ...
    setGlobalFilter,
} = useTable(
    {
        globalFilter: ourGlobalFilterFunction
    },
    ...
    useGlobalFilter,
);
Enter fullscreen mode Exit fullscreen mode

See Code Sandbox: https://codesandbox.io/s/specific-columns-global-filter-n1k4v?file=/src/Table.tsx

However, in my case this is inside a Table component which I use in a couple of places, so let's make ourGlobalFilterFunction take arbitrary column names for filtering. We'll also pass the filter query as a prop to Table.

interface TableProps {
    filters: string[];
    filter: string;
}

const Table: React.FC<TableProps> = ({
    filters,
    filter,
}): React.ReactComponent => {

    const ourGlobalFilterFunction = useCallback(
        // This is Typescript if you're using JS remove the types (e.g. :string)
        (rows: Row<T>[], ids: IdType<T>[], query: string) => {
            return rows.filter((row) => 
                for (const filter of filters) {
                    return row.values[filter].includes(query)
                }
            );
        },
        [filters],
    );

    const {
      ...
      setGlobalFilter,
    } = useTable(
        {
            globalFilter: ourGlobalFilterFunction
        },
        ...
        useGlobalFilter,
    );

    useEffect(() => {
        setGlobalFilter(filter) // Set the Global Filter to the filter prop.
    }, [filter, setGlobalFilter]);

    return (
        ...
    );
}
Enter fullscreen mode Exit fullscreen mode

Code Sandbox: https://codesandbox.io/s/filter-props-global-filter-i18bd?file=/src/Table.tsx

Finally, I'd like this to do fuzzy text filtering. We'll use the match-sorter library for this

npm install match-sorter
Enter fullscreen mode Exit fullscreen mode
import { matchSorter } from 'match-sorter';

...

const globalFilter = useCallback(
    (rows: Row<T>[], ids: IdType<T>[], query: string) => {
        return matchSorter(rows, query, {
            keys: filters.map((columnName) => `values.${columnName}`),
        });
    },
    [filters],
);
Enter fullscreen mode Exit fullscreen mode

Code Sandbox: https://codesandbox.io/s/fuzzy-text-global-filter-rcy1f?file=/src/Table.tsx

Top comments (1)

Collapse
 
anurella profile image
Anurella

Thank you for this