Building a Filter Component in React

Photo by Jess Bailey on Unsplash

Building a Filter Component in React

ยท

4 min read

I was working on a small project and needed the ability for users to search and also filter through the database. I had some hiccups working on the filter feature and in the course of my research, I did not come across any helpful article to assist me. I was able to resolve the issue and chose to write about the process ๐Ÿ˜ƒ

In this article, I'll walk us on how to build a Filter Component in React. If you want to learn how to build a Search Component check my article here.

This article is a continuation of the search article that covers setting up React, installation of axios, displaying data from the api using axios, and of course, building the search component. We used https://restcountries.com/ API to fetch countries.

I'm assuming you already know how to do the aforementioned, if not I strongly advise you to go through the article.

To get started, we create a Filter component in the Components folder. We use the select element to create options we can filter with. In this case, we would filter by continents.

import React from 'react';

const Filter = () => {
  return (
    <>
      <select name='country' id='country'>
        <option value='All'>Filter by Continent</option>
        <option value='Antarctica'>Antarctica</option>
        <option value='Asia'>Asia</option>
        <option value='Africa'>Africa</option>
        <option value='Europe'>Europe</option>
        <option value='North America'>North America</option>
        <option value='South America'>South America</option>
        <option value='Oceania'>Oceania</option>
      </select>
    </>
  );
};

export default Filter;

Now we need a function to handle our filter.

In App.js, we import the Filter component, then we create a function called handleFilter which is passed as a prop to the Filter component with e.target.value as an argument. The state of filter(setFilterV) is updated to whatever the user selects as an option.

import Filter from './Components/Filter';
 const [filterV, setFilterV] = useState('All');

const handleFilter = (filterValue) => {
    setFilterV(filterValue)

};

<Filter onChange={(e)=>handleFilter(e.target.value)}/>

In the Filter component, we pass onChange as a prop

const Filter = ({ onChange }) => {
  return (
    <>
      <select name='country' id='country' onChange={onChange}>
        <option value='All'>Filter by Continent</option>
        <option value='Antarctica'>Antarctica</option>
        <option value='Asia'>Asia</option>
        <option value='Africa'>Africa</option>
        <option value='Europe'>Europe</option>
        <option value='North America'>North America</option>
        <option value='South America'>South America</option>
        <option value='Oceania'>Oceania</option>
      </select>
    </>
  );
};

To test if this works, we can console.log(filterV) and inspect the result in our console.

Still, on our handleFilter function, we need to filter through our countries array and return countries with continents that match the one in our filter array. Since country.continent is an array we can use the javascript method .includes to return exact matches.

  const handleFilter = (filterValue) => {
    console.log(filterValue);
    setFilterV(filterValue);

    const filterCountry = countries.filter((country) =>
      country.continents.includes(filterValue)
    );

  };

Now we have to make a little adjustment to our Search component. We create a new state called filteredResults

 const [filteredResult, setFilteredResult] = useState([])

Then we refactor our code and join both the handleSearch function and filteredSearch function into one function. This is similar to the way we wrote the handleFilter function.

 const filteredSearch = (searchValue)=>{
    setSearch(searchValue);
    const searchAll = countries.filter((country) =>
    country.name.common.toLowerCase().includes(search.toLowerCase())
  );
  setFilteredResult(searchAll)
  }

In the Search component we passfilteredSearch to the onChange event as props with e.target.value as an argument.

       <Search onChange={(e)=>filteredSearch(e.target.value)} value={search} />

Back on the handleFilter function, we also update filteredResult state with filterCountry

setFilteredResult(filterCountry);

Now the only thing left to do is to change the variable we loop through to display the appropriate data.

{filteredSearch.map(country=><Country key={country.cca3} country={country} />)}

becomes

{filteredResult.map(country=><Country key={country.cca3} country={country} />)}

In the Render part of App.js we have to make a few changes so that the application renders our filtered search. We set a condition to loop through filteredResult when the value of filter is not equal to All and to display all countries when the value of filter is equal to All.

{filter !== 'All' ? 
    filteredResult.map(country=>
       <Country key={country.cca3} country={country} />) 
    : countries.map(country=>
       <Country key={country.cca3} country={country} />) 
      }

If you are following from the search article then the render changes to this

{search === '' || filterV === 'All' ? (
        []
      ) : filteredResult.length > 10 ? (
        <p>Too many searches, specify another filter</p>
      ) : filterV !== 'All' ||
        (filteredResult.length <= 10 && filteredResult.length > 1) ? (
        filteredResult.map((country) => (

          <CountryName
            key={country.cca3}
            country={country}
          />
        ))
      ) : (
        filteredResult.map((country) => (
          <Country key={country.cca3} country={country} />
        ))
      )}

All done now! ๐Ÿ˜„ we can tidy up our code by clearing the console.logs and testing to make sure the Search feature still works.

I hope this article helps someone get unstuck, and once again pardon all grammatical errors. If there is a better way this can be achieved I would like to learn from you in the comments ๐Ÿ˜ƒ

https://fullstackopen.com/en/ is a good resource to learn React. don't stall, start now! โœŒ๏ธ ๐Ÿ˜ƒ

ย