Using a React Table with Client-Side Pagination
Tags: react, javascript, programming, components
Published: 2021-01-28 03:47:57

If you’d prefer to watch rather than read:
https://youtu.be/v9E7moqUJ40

Pagination is a simple navigation technique that allows you to divide content into pages. It is very useful when you want to display a large recordset on multiple pages, for example in a table with a huge amount of data.

In this article, I’ll be teaching you how to use a React Table with client-side pagination using [react-rainbow-components](https://react-rainbow.io/). To accomplish this tutorial, you must have a general background in React, Node.js, and Yarn.

## Project setup

### What you will need:
- Node.js
- Yarn
- Your favorite IDE (For this tutorial, I will use VSCode)

### Add dependencies
For this project, I will use a new create-react-app project. If you want to know more and how to initialize a project, see: https://create-react-app.dev/.

Once in the root of your project, let’s install react-rainbow-components and react-query:
```
$ yarn add react-rainbow-components react-query
```

Once you have your new app with all dependencies installed, we should be ready to code!

## Coding

###Importing dependencies

Now we will start by importing react-query and react-rainbow-components:

```js
import { QueryClient, QueryClientProvider, useQuery } from 'react-query';
import { Table, Column } from 'react-rainbow-components';
import './App.css';
```

### Creating the service

Create a function that fetches a list with all the countries:

```js
const API_URL = "https://sampleapis.com/countries/api/countries";
const fetchCountries = async () => {
    const result = await fetch(API_URL);
    return result.json();
};
```
I am using a free API that will return a list with certain information about the countries like name, capital, population, currency, and more.

### Countries Component

Now let’s add a Countries component that will render a Table with all the countries returned by the API call:
```js
function Countries() {
    const { isLoading, data } = useQuery(
        "countries",
        fetchCountries,
    );
    return (
        <Table
            className="countries-table"
            keyField="name"
            isLoading={isLoading}
            data={data}
            variant="listview"
        >
            <Column header="Name" field="name" />
            <Column header="Capital" field="capital" />
            <Column header="Population" field="population" />
            <Column header="Currency" field="currency" />
        </Table>
    );
}
```

To make the call to the API, I used useQuery hook from the react-query package (https://github.com/tannerlinsley/react-query). This hook will manage the fetch for us and return an object with data, isLoading, error, and more. Thus, we avoid the need to maintain the different states of the fetch process. Also, it provides other advantages like caching, updating out-of-date data in the background, performance optimizations, and many more. If you want to know more about react-query visit its documentation https://react-query.tanstack.com/overview.

The react-rainbow-components Table needs a keyField prop which is required, it can be any field in the data that is unique like an id or a key representing the document or the row in the database. In this case, I used the country name which is unique. The Table also receives an isLoading that will render the loading state when it is true and data that is an array of objects with the data to show in the table. The columns are represented as children of the Table, and they receive a header that is a simple string that will show in the column header. Also, receive a field that represents the key in the data that its value will be shown in the column.

### App Component
Next, we will add an app component that is exported and it only has the QueryClientProvider wrapper around the Countries component.
```js
const queryClient = new QueryClient();
function App() {
    return (
        <QueryClientProvider client={queryClient}>
            <Countries />
        </QueryClientProvider>
    );
}
export default App;
```
The QueryClient is used to interact with the cache managed by react-query. By wrapping your application with the QueryClientProvider you can access the QueryClient anywhere in the app.

### Styling
Now we will add some simple styles to the Table component:

```js
.countries-table {
    padding: 40px;
    background-color: rgb(244, 246, 249);
    height: 100%;
    min-height: 100vh;
}
```

When save and reload the page you will see something like:
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/plcv891njwn3b1eubmp3.png)

You can see it and play in this [sandbox](https://codesandbox.io/s/elated-lederberg-zpo4q?file=/src/App.js):


### Problems with this solution
Now we have a large table that shows all countries, but this can cause performance issues since we are rendering too many rows on the page, and creating such an amount of DOM elements is costly.
How to solve this? Here is when client-side pagination comes into play. If your collection or table does not have too many records (hundreds or a few thousand), then you can fetch all of them and do client-side pagination as we will do next.

### Client-Side pagination
To achieve the client-side pagination, we can use the TableWithBrowserPagination component from the react-rainbow-components library. The only thing you need to do is import it and pass the `pageSize` prop with the number of records you want to show per page.

Replace the react-rainbow-components Table import line to:
```js
import { TableWithBrowserPagination, Column } from 'react-rainbow-components';
```

Here we only change `Table` for `TableWithBrowserPagination`.

Next, change the Countries component to use the TableWithBrowserPagination:
```js
function Countries(params) {
    const { isLoading, data } = useQuery(
        "countries",
        fetchCountries,
    );
    return (
        <TableWithBrowserPagination
            className="countries-table"
            keyField="name"
            isLoading={isLoading}
            data={data}
            variant="listview"
            pageSize={15}
        >
            <Column header="Name" field="name" />
            <Column header="Capital" field="capital" />
            <Column header="Population" field="population" />
            <Column header="Currency" field="currency" />
        </TableWithBrowserPagination>
    );
}
```

There were two simple changes in this code. First, we change Table for TableWithBrowserPagination and add a new prop pageSize with the value of 15, which means that it will render only 15 rows per page.

Now we have:
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/tzpgdublfxstg8xynt0m.png)

As you can see, there is pagination at the bottom of the page. Now you can move through the different pages. All the data is already loaded, but we only render 15 rows per page. In this way, we avoid the performance issues caused by creating too many DOM elements.

## Conclusion
That’s all folks!

Only with a few lines of code, we have used a table with client-side pagination. The main takeaway is that we can achieve a good user experience by simply splitting the data into pages. Not only does it solve the performance issue, but it also gives us a nice way to represent data since showing a table with a large scroll bar can be annoying to the user.

Thanks for reading!