Introduction

Table user interfaces are ubiquitous, mostly used, and organized UI preferred by users and developers. It makes the data look simple and easily accessible. Being a ReactJS developer, you might have heard of React Table V7; few might have implemented it too. If you are looking for a tutorial explaining React Table V7 with an Example, you have chosen the right blog. Today we are here with a react-table tutorial for you.

I understand how challenging it could be when you are trying to learn something new, but I also know how interesting is that! Isn’t it?

Refer to the next section that includes the points covered in this tutorial – React Table Tutorial – Project Setup, Installation, useTable, and useFilter.



React Table Tutorial Goal: useTable and useFilter

Before starting the development process let’s have a look at the below video so that you can understand what are we building.

React Table v7

The creator of React Table – Tanner Linsley, launched React Table v7 in March 2020. We might remember using the class component of react-table, but now the library provides the Hooks-based APIs and plugins for creating a hassle-free React Table. The release is considered a significant change as the approach to creating a table, table UI, and style has changed.

New Features in React Table v7

Considering React Table release note, here are the new features in React Table v7:

  • Headless (100% customizable, Bring-your-own-UI)
  • Lightweight (5kb – 14kb+ depending on features used and tree-shaking)
  • Sorting (Multi and Stable)
  • Filters
  • Animatable
  • Row Expansion
  • Column Ordering
  • Virtualizable
  • Server-side/controlled data/state
  • Auto out of the box, fully controllable API
  • Extensible via a hook-based plugin system
  • Row Selection
  • Resizable
  • Pivoting & Aggregation

Project Set-Up

Create ReactJS project using the below command.

Copy Text
npx create-react-app react-table-demo

Install react-table and Axios

Install react-table and axios.

Copy Text
npm install react-table axios --save  //npm
yarn add react-table axios  //yarn

Looking for a Reactjs Development Company?
Built real-time web applications with dynamic UIs with one of the profound ReactJS Development Company in the industry.

Getting started with React Table Example

After done with project setup and installation, follow these steps to implement React Table Example. I’ll be writing the entire code in two files, i.e.,

  • App.js – main file
  • TableContainer.js – having a Table component.

Importing Axios and Hooks

Copy Text
import React, { useState, useEffect, useMemo } from "react";
import axios from "axios";

Initializing state using useState

Copy Text
const [data, setData] = useState([]);

Fetching Data using Axios

Copy Text
useEffect(() => {
   axios("http://api.tvmaze.com/search/shows?q=girls")
     .then((res) => {
       setData(res.data);
     })
     .catch((err) => console.log(err))
 }, []);
  • I have called “http://api.tvmaze.com/search/shows?q=girls“
  • If the promise is resolved, it will execute then block, in which we will store the response in the state using setData(res.data)
  • And if the promise is rejected, it will execute the catch block and console the error.

Defining Columns

After preparing our data, let’s define the columns of the Table. The column structure would consist-

  • Header – the name of the column
  • Accessor – key in data.

We will wrap it inside hook useMemo as far as the optimization is concerned.

Copy Text
const columns = useMemo(
   () => [
     {
       Header: "TV Show",
       columns: [
         {
           Header: "Name",
           accessor: "show.name"
         },
         {
           Header: "Type",
           accessor: "show.type"
         },
         {
           Header: "Language",
           accessor: "show.language"
         },
         {
           Header: "Official Site",
           accessor: "show.officialSite",
           Cell: ({ cell: { value } }) => value ? {value} : "-"
         },
         {
           Header: "Rating",
           accessor: "show.rating.average",
           Cell: ({ cell: { value } }) => value || "-"
         },
         {
           Header: "Status",
           accessor: "show.status",
         },
         {
           Header: "Premiered",
           accessor: "show.premiered",
           Cell: ({ cell: { value } }) => value || "-"
         },
         {
           Header: "Time",
           accessor: "show.schedule.time",
           Cell: ({ cell: { value } }) => value || "-"
         },
       ]
     }
   ]
 )

You might be wondering why I have written “show.name”, “show.type”, “show.rating.average” and so on. It is because the data is inside the show object, and for accessing the data, we will use show. as the prefix. Here is the sample of data-

Defining Columns

Custom Cell

Copy Text
{
  Header: " Official Site ",
  accessor: " show.officialSite ",
  Cell: ( props ) => {
 	return < YourComponent { ...props } / >
  }
},

We can have the custom cell for each row as shown above. A cell has access to the values of each row; you can console props to see what it consists of.

Our demo will implement the custom cell to check whether show.officalSite has the value or not. If it has the value then it will return or “-”

Copy Text
{
  Header: "Official Site",
  accessor: "show.officialSite",
  Cell: ({ cell: { value } }) => value ? 
       {value} : "-"
},

Implement useTable Hook in React Table Tutorial

We will create another file named – TableContainer.js in which we will build our Table component using the useTable hook.

It will take two properties: data and columns, which we have defined in the above sections.

  • Data consists of the data of the API response
  • Columns is an array of objects for defining table columns.
Copy Text
import React from "react";
import { useTable } from "react-table";
 
export default function Table({ columns, data }) {
 const {
   getTableProps,
   getTableBodyProps,
   headerGroups,
   rows,
   prepareRow,
 } = useTable({
   columns,
   data,
 })
 
 return (
   < table {...getTableProps()} >
     < head >
       {headerGroups.map(headerGroup => (
         < tr {...headerGroup.getHeaderGroupProps()} >
           {headerGroup.headers.map(column = > (
             < th {...column.getHeaderProps()}>{column.render('Header')}< /th >
           ))}         
       ))}
     < /thead >
     < tbody {...getTableBodyProps()} >
       {rows.map((row, i) => {
         prepareRow(row)
         return (
           < tr {...row.getRowProps()} >
             {row.cells.map(cell => {
               return < td {...cell.getCellProps()}>{cell.render('Cell')}< /td >
             })}
           < /tr >
         )
       })}
     < /tbody >
   < /table >
 )
}

Rendering React Table

Import the Table from the TableContainer.js and then render on the UI using

Copy Text
import Table from './TableContainer'
 
< div className="App" >
    < h1 >< center >React Table Demo< /center >< /h1 >
    < Table columns={columns} data={data} />
< /div >

After implementing the above code snippets, following your App.js and TableContainer.js will look like this –

// App.js

Copy Text
import React, { useState, useEffect, useMemo } from "react";
import axios from "axios";
import { useTable } from "react-table";
 
import './App.css';
 
function Table({ columns, data }) {
  const {
   getTableProps,
   getTableBodyProps,
   headerGroups,
   rows,
   prepareRow,
 } = useTable({
   columns,
   data,
 })
 
 return (
   < table {...getTableProps()} >
     < head >
       {headerGroups.map(headerGroup => (
         < tr {...headerGroup.getHeaderGroupProps()}>
           {headerGroup.headers.map(column => (
             < th {...column.getHeaderProps()}>{column.render('Header')}< /th >
           ))}
         < /tr >
       ))}
     < /thead >
     < tbody {...getTableBodyProps()}>
       {rows.map((row, i) => {
         prepareRow(row)
         return (
           < tr {...row.getRowProps()}>
             {row.cells.map(cell => {
               return {cell.render('Cell')}
             })}
           < /tr >
         )
       })}
     < /tbody >
   < /table >
 )
}
 
function App() {
 const [data, setData] = useState([]);
 
 useEffect(() => {
   axios("http://api.tvmaze.com/search/shows?q=girls")
     .then((res) => {
       setData(res.data);
     })
     .catch((err) => console.log(err))
 }, []);
 
 const columns = useMemo(
   () => [
     {
       Header: "TV Show",
       columns: [
         {
           Header: "Name",
           accessor: "show.name"
         },
         {
           Header: "Type",
           accessor: "show.type"
         },
         {
           Header: "Language",
           accessor: "show.language"
         },
         {
           Header: "Official Site",
           accessor: "show.officialSite",
           Cell: ({ cell: { value } }) => value ? {value} : "-"
         },
         {
           Header: "Rating",
           accessor: "show.rating.average",
           Cell: ({ cell: { value } }) => value || "-"
         },
         {
           Header: "Status",
           accessor: "show.status",
         },
         {
           Header: "Premiered",
           accessor: "show.premiered",
           Cell: ({ cell: { value } }) => value || "-"
         },
         {
           Header: "Time",
           accessor: "show.schedule.time",
           Cell: ({ cell: { value } }) => value || "-"
         },
       ]
     }
   ]
 )
 
 return (
   < div className="App" >
     < h1 >< center >React Table Demo< /center >< /h1 >
     < Table columns={columns} data={data} / >
   < /div >
 );
}

export default App;

// TableContainer.js

Copy Text
import React from "react";
import { useTable } from "react-table";
 
export default function Table({ columns, data }) {
 const {
   getTableProps,
   getTableBodyProps,
   headerGroups,
   rows,
   prepareRow,
 } = useTable({
   columns,
   data,
 })
 
 return (
   < table {...getTableProps()}>
     < head >
       {headerGroups.map(headerGroup => (
         < tr {...headerGroup.getHeaderGroupProps()}>
           {headerGroup.headers.map(column => (
             < th {...column.getHeaderProps()}>{column.render('Header')}
           ))}
         < /tr >
       ))}
     < /thead >
     < tbody {...getTableBodyProps()} >
       {rows.map((row, i) => {
         prepareRow(row)
         return (
           < tr {...row.getRowProps()}>
             {row.cells.map(cell => {
               return {cell.render('Cell')}
             })}
           < /tr >
         )
       })}
     < /tbody >
   < /table >
 )
}

After running the command npm run start you will see something like this-

React Table Demo

Implement useFilter Hook

Now, moving on to useFilter and useGlobalFilter in our application. According to our UI, this will be our project structure.

Implement useFilter Hook

We will implement the default filter and select column filter. For that, we will

  • Update App.js
  • TableContainer.js

Create a new file named – Filter.js (which will have functional components for Filter views)

Without further ado, let’s create Filter.js and define React table components for Filter UI.

Defining Filter Component for UI

In this React Table demo, we will implement three filter views –

  • Default Filter for Columns: It will render text input, and the column data is filtered based on the text entered.
  • Global Filter: It will render text input but not just for columns; the entire table data is filtered based on the text entered.
  • Select Filter for Column: It will render select input, and the column data is filtered based on the option selected from the list.

We will create a common file named Filter.js (or with any suitable name) from where we will export the above-mentioned functional components for readability purposes.

// Filter.js

Copy Text
import { React, useMemo, useState } from "react";
import { useAsyncDebounce } from "react-table";
import { Label, Input } from "reactstrap";
 
// Component for Global Filter
export function GlobalFilter({ 
   globalFilter, 
   setGlobalFilter 
}) {
 const [value, setValue] = useState(globalFilter);
 
 const onChange = useAsyncDebounce((value) => {
   setGlobalFilter(value || undefined);
 }, 200);
 
 return (
   <div>
     <Label>Search Table: </Label>
     <Input
       value={value || ""}
       onChange={(e) => {
         setValue(e.target.value);
         onChange(e.target.value);
       }}
       placeholder=" Enter value "
       className="w-25"
       style={{
         fontSize: "1.1rem",
         margin: "15px",
         display: "inline",
       }}
     />
   </div>
 );
}
 
// Component for Default Column Filter
export function DefaultFilterForColumn({
 column: {
   filterValue,
   preFilteredRows: { length },
   setFilter,
 },
}) {
 return (
   <Input
     value={filterValue || ""}
     onChange={(e) => {
       // Set undefined to remove the filter entirely
       setFilter(e.target.value || undefined);
     }}
     placeholder={`Search ${length} records..`}
     style={{ marginTop: "10px" }}
   />
 );
}
 
// Component for Custom Select Filter
export function SelectColumnFilter({
 column: { filterValue, setFilter, preFilteredRows, id },
}) {
 
 // Use preFilteredRows to calculate the options
 const options = useMemo(() => {
   const options = new Set();
   preFilteredRows.forEach((row) => {
     options.add(row.values[id]);
   });
   return [...options.values()];
 }, [id, preFilteredRows]);
 
 // UI for Multi-Select box
 return (
   <select
     value={filterValue}
     onChange={(e) => {
       setFilter(e.target.value || undefined);
     }}
   >
     <option value="">All</option>
     {options.map((option, i) => (
       <option key={i} value={option}>
         {option}
       </option>
     ))}
   </select>
 );
}

Explanation

  • What is the use of useAsyncDebounce? – React table provides useAsyncDebounce to avoid the multiple re-renders caused due to side-effects and to use the latest one. Back-to-back state side-effects take place that triggers multiple renders. So, rather than handling it manually, React Table provides a hook to debounce the rapid side-effects.
    Here, we have little data, so that we won’t realize the importance of useAsyncDebounce. But, consider, if we have thousands of data filtered, then the continuous state changes and side-effects are much costlier than this demo app.

    A good developer takes care of the performance even while coding for a demo application. Try avoiding trash coding.

  • The setfilter, filterValue, and preFilterRows are column properties used for specific columns. We have destructured the column prop and used them to get the filter values of respective columns.

Rendering Filter Component

For GlobalFilter and DefaultFilterForColumn

Open TableContainer.js and Import components and hooks-

Copy Text
import { useTable, useFilters, useGlobalFilter } from "react-table";
import { GlobalFilter, DefaultFilterForColumn} from "./Filter";

Pass DefaultFilterForColumn to useTable hook as a default filter for all the columns. So by default, your columns will have these components as filters unless you provide a custom filter or disable the filter.

Copy Text
useTable(
  {
    columns,
    data,
    defaultColumn: { Filter: DefaultFilterForColumn },
  },
 useFilters,
 useGlobalFilter

Now for rendering the UI, use the following code-

Copy Text
{/* Rendering Global Filter */}
 

 
{/* Rendering Default Column Filter */}
 
{column.canFilter ? column.render("Filter") : null}

Your entire TableContainer.js will look like this-

// TableContainer.js

Copy Text
import { React } from "react";
import { useTable, useFilters, useGlobalFilter } from "react-table";
import { GlobalFilter, DefaultColumnFilter } from "./Filter";
 
export default function Table({ columns, data }) {
  const {
   getTableProps,
   getTableBodyProps,
   headerGroups,
   rows,
   state,
   visibleColumns,
   prepareRow,
   setGlobalFilter,
   preGlobalFilteredRows,
 } = useTable(
   {
     columns,
     data,
     defaultColumn: { Filter: DefaultFilterForColumn },
   },
   useFilters,
   useGlobalFilter
 );
 
 return (
   <table {...getTableProps()}>
     <thead>
       <tr>
         <th
           colSpan={visibleColumns.length}
           style={{
             textAlign: "center",
           }}
         >
           {/* Rendering Global Filter */}
           <GlobalFilter
             preGlobalFilteredRows={preGlobalFilteredRows}
             globalFilter={state.globalFilter}
             setGlobalFilter={setGlobalFilter}
           />
         </th>
       </tr>
       {headerGroups.map((headerGroup) => (
         <tr {...headerGroup.getHeaderGroupProps()}>
           {headerGroup.headers.map((column) => (
             <th {...column.getHeaderProps()}>
               {column.render("Header")}
               {/* Rendering Default Column Filter */}
               <div>
                 {column.canFilter ? column.render("Filter") 
                  :null}
               </div>
             </th>
           ))}
         </tr>
       ))}
     </thead>
     <tbody {...getTableBodyProps()}>
       {rows.map((row, i) => {
         prepareRow(row);
         return (
           <tr {...row.getRowProps()}>
             {row.cells.map((cell) => {
               return <td {...cell.getCellProps()}>
           {cell.render("Cell")}
         </td>;
             })}
           </tr>
         );
       })}
     </tbody>
   </table>
 );
}

For using SelectColumnFilter,

  • Open App.js where we have defined the array of columns.
  • Import SelectColumnFilter.
  • Add Filter: SelectColumnFilter to a particular object of the column.
Copy Text
{
  Header: "Status",
  accessor: "show.status",
  Filter: SelectColumnFilter,
  filter: "includes",
},

If you disable filter on any particular column, add the following line of code-

Copy Text
{
  Header: "Premiered",
  accessor: "show.premiered",
  // disable the filter for particular column
  disableFilters: true, 
  Cell: ({ cell: { value } }) => value || "-",
},

How does Column Filter work in React Table?

Do you remember we added a line for implementing column filter-

Copy Text
<div>{column.canFilter ? column.render("Filter") : null}</div>

The “Filter” is the property in the column definition. It will render whichever component is given as a value to the Filter key.

Here we have used defaultcolumn, so no need to define Filter for all the columns but we have to define the Filter key for custom filters (e.g. SelectColumnFilter)

The condition of column.canFilter will be executed and it will render component defined to key Filter.

Here we have mentioned the custom filter, SelectColumnFilter, in the object and set DefaultFilterForColumn as a default shown filter.

Github Repository: react-table-example

Feel free to visit the source code of the demo application- react-table-example.

Conclusion

So, this was about how to filter your table data using the useFilter hook. I hope the React Table tutorial was helpful for you. If you have any questions or suggestions, feel free to comment below.

If you are a ReactJs enthusiast, check the ReactJS Tutorials page with more tutorials and its respective github repository.

At Bacancy, developers try their best to come up with optimum solutions and affordable problem-solving approaches. If you are looking for a helping hand for your project, contact us to hire React developers without wasting a minute.

React JS Tutorials

Connect Now

Get In Touch

[email protected]

Your Success Is Guaranteed !

We accelerate the release of digital product and guaranteed their success

We Use Slack, Jira & GitHub for Accurate Deployment and Effective Communication.

How Can We Help You?