Sitemap
Press enter or click to view image in full size
Photo by Alexandru Acea on Unsplash

How to Create a Filterable List in React with the Context API

6 min readJun 9, 2021

--

In this tutorial, we will focus on how we can create a filterable list page in React using Material UI. The idea is to provide full control over the page design as we will have different components for Filter and Table that can be placed as per our page UI.

In nutshell, we will override some MaterialUI components for Filter and Table. Then we will use a context that will wrap our page and on our page, we can place the filter and table at any place. The filter and table component will use the context to update different attributes and that will allow our page component to fetch or modify data. Let’s see this in detail.

Define the requirements

For this tutorial we will need the following components:

  1. Filter, that has different types of input for filtering the list
  2. Table, to display our list data
  3. Pagination, allow the user to navigate through data

We will also need a way to get some data for the tables. We will be using json-server.

Setup Project

Let’s init a new react project. We will use CRA so please run this command.

create-react-app filtered-list

Now we need to install our dependencies for this tutorial. Please run this command inside the project directory. I use yarn but you can also use npm.

yarn add @material-ui/core @material-ui/data-grid @material-ui/icons @material-ui/lab react-router-dom
//Install Json Server
yarn global add json-server

Once we have all the dependencies installed, let’s test if the installation went well by running yarn start command. If all goes well you will see the default app page with React logo in your browser. If you get any errors, please fix them before we go ahead.

Now, let's move ahead and create the required components.

Filter Component

First, we will set up a simple filter component, that renders different kinds of input based on the given list. At a minimum, we need the following attributes for each filter, an id, a type, and a label. The label will be displayed on the input fields, the type will determine which input type is required and id will be used to update the filter value. Based on this let’s first create the filter component. Please see below the code:

It’s a very simple component, takes a list of filters needed and renders them based on the given type. Currently, I have used Text input but there is no limitation. You can add more types and you have all the controls over the input component.

Now update our App.js to see if the component working correctly. Here is the gist of the updated App page

Press enter or click to view image in full size
Filters in App.js

Ok, so this looks pretty good. Now we have our filters working fine, let's move to set up our Table component.

Table Component

For this tutorial, I am using a Material-UI Table. We will use their example and update it to our needs a bit. The table basically has 3 main components, head, body, and pagination.

Let’s copy EnhancedTableHeadfrom their example to create our table head and update it to our needs. We will need to control sorting and, selection. To do that we will add a couple of props and render conditions.

As you can see, we’ve updated EnhancedTableHead component from the MaterialUI example and added a few more props and rendering conditions. For example, we can either allow sorting or disable it by setting canSort. We can also usecanSelectAll property to render a checkbox that allows a user to select all of the rows and take some action.

Similar to the table head, we need to update the pagination component and add some control to it. Here is the updated code

<TablePagination
rowsPerPageOptions={[5, 10, 25]}
component="div"
rowsPerPage={rowsPerPage}
page={page}
count={count}
onChangePage={handleChangePage}
onChangeRowsPerPage={handleChangeRowsPerPage}
/>

As you can see we are now controlling some props and added a few callbacks as per our requirement. This is how it will render on the page

Now, look at setting up the Table with the updated heading and pagination. Here is the full code of how the Table component looks like. It's mostly the same as the example on the MaterialUI portal but with a few more controls and callbacks. Here is the updated code

Until now, we have a filter component and a table component. Now let's create a context and use them in both component

Create List Provider and context

We have both of our components ready. We can now use them directly on any of the pages but that will require us to add more code to handle different action user will take on the filters and the table. If we have many similar pages we will end up with lots of duplicate code with different UI but doing the same thing for list and filters. To avoid that we will create a context. Here is the code

It’s a very basic context, and has a bunch of methods to handle table and filter action and update the state.

Let’s extend our Filter component to use the list context. We should not modify our main Filter component because that will allow us to use it in other projects where we don't need it based on the context. Here is the updated code

Similar to that we will modify our table component as well to use the list context. Here is the updated code

We are now pretty much done with that. All we need is to create a simple page that displays our data and allows filtering on that. Let's set up a page to render the above component we created.

Setup Page with Filter and Table

Earlier we created 2 components, a Filter and a Table. We have then extended them to use a list context. Now let's put everything together and create a simple page. Here is how I do that

and update our App.js to following

So, we added a bunch of Route on the App.js. When the app renders, it will redirect to a /user/list route where it will render our page that has the Filter and Table component.

Now we will run our {json server} with a JSON file so we can serve some data to our list. So please create a db.json file and have a user list. Here is an example of how the JSON should be structured.

{
"users": [{
}]
}

Now run our JSON server with the following command. Make sure it runs on a different port than our react app is running. Make sure the path to the DB file is relative.

json-server --port 3001 --watch db.json

Now if you navigate to http://localhost:3001/users you will see the list of users you have set up in the db.json.

Now move on to modifying our List page to fetch the user data and display it. Please update the page code with following

function UserListPage() {
...
useEffect(() => {
setUsers([])
loadUsers();
}, [list.filters, list.pagination, list.sort])
const loadUsers = () => {
fetch(`http://localhost:3001/users?${new URLSearchParams(list.filters)}`)
.then(response => response.json().then(json => ({
total: parseInt(response.headers.get('X-Total-Count'), 10) || 10,
data: json
}))
).then(response => {
let { total, data } = response;
setTotalUsers(total)
setUsers(data)
})
}
...

As you can see we added a useEffect which will run whenever the list context has updated filter, pagination, or sorting. We also added a function to load our user.

Conclusion

That’s it now. We will now have a filterable list that is highly customizable and you can place the different components in different places as per your UI requirements. You can find the full source code on GitHub.

Thank you for reading and sharing.

More content at plainenglish.io

--

--