How to filter an Array of Objects in React?
Tags: react
Published: 2022-09-28 15:03:46

In my previous article, I explained how to [filter numbers and strings in React](https://www.codingdeft.com/posts/react-filter/). In this article, we will see how to filter an array of objects.

{% embed https://youtu.be/jN_s2uKntmc %}

## Project setup

Create a react app using the following command:

```bash
npx create-react-app react-filter-object-array
```

Add the following css to `index.css`:

```css
body {
  display: flex;
  justify-content: center;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  margin: 10px 0;
  border: 1px solid;
  padding: 10px;
}
.experience_filter {
  display: flex;
  gap: 6px;
  margin: 10px 0;
}
.experience_filter button {
  cursor: pointer;
  border: 1px solid;
  border-radius: 4px;
  padding: 4px;
  background-color: white;
}
.experience_filter button.selected {
  background-color: wheat;
}
```

Update the `App.js` with the following code:

```jsx
import { useState } from "react"

const employees = [
  {
    id: 1,
    name: "Tobe",
    experience: 4,
    department: "Accounting",
  },
  {
    id: 2,
    name: "Jolee",
    experience: 13,
    department: "Services",
  },
  {
    id: 3,
    name: "Muhammad",
    experience: 14,
    department: "Training",
  },
  {
    id: 4,
    name: "Hubie",
    experience: 5,
    department: "Sales",
  },
  {
    id: 5,
    name: "Yoshiko",
    experience: 16,
    department: "Services",
  },
  {
    id: 6,
    name: "Beatrix",
    experience: 17,
    department: "Human Resources",
  },
  {
    id: 7,
    name: "Jacob",
    experience: 4,
    department: "Engineering",
  },
  {
    id: 8,
    name: "Koren",
    experience: 4,
    department: "Accounting",
  },
  {
    id: 9,
    name: "Marissa",
    experience: 20,
    department: "Support",
  },
  {
    id: 10,
    name: "Rufe",
    experience: 18,
    department: "Training",
  },
]

function App() {
  const [filteredEmployees, setFilteredEmployees] = useState(employees)
  return (
    <div className="App">
      <ul>
        {filteredEmployees.map(employee => {
          const { name, experience, department, id } = employee
          return (
            <li key={id}>
              <div>
                Name: <strong>{name}</strong>
              </div>
              <div>Experience: {experience} year(s)</div>
              <div>Department: {department}</div>
            </li>
          )
        })}
      </ul>
    </div>
  )
}

export default App
```

Here we have a list of 10 employees and we are [looping](https://www.codingdeft.com/posts/react-for-loop/) through them
and displaying each employee's information on a card.

![list of employees](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ufuhdyhpdv8wpjj6503l.png)

## Filtering based on department

You can filter the employees by department using the following function:

```js
const filterByDepartment = department => {
  setFilteredEmployees(
    employees.filter(employee => {
      return employee.department === department
    })
  )
}
```

Here we are using the [array filter function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter), and passing a callback to it. The callback will be called for each item in the employees array. If the callback returns true for an employee, only that employee will be added to the array, which will be returned by the filter function. We are setting the returned array to the `filteredEmployees` state.

Now, let's add a dropdown to list unique departments:

```jsx
import { useState } from "react"

const employees = [
  //...
]

function App() {
  const [filteredEmployees, setFilteredEmployees] = useState(employees)

  const filterByDepartment = department => {
    setFilteredEmployees(
      employees.filter(employee => employee.department === department)
    )
  }

  // Using Set to filter unique values
  const departments = Array.from(
    new Set(employees.map(employee => employee.department))
  )

  return (
    <div className="App">
      <select onChange={e => filterByDepartment(e.target.value)}>
        <option value="" disabled default selected>
          Select department
        </option>

        {departments.map(department => {
          return <option key={department}>{department}</option>
        })}
      </select>
      <ul>
        {filteredEmployees.map(employee => {
          const { name, experience, department, id } = employee
          return (
            <li key={id}>
              <div>
                Name: <strong>{name}</strong>
              </div>
              <div>Experience: {experience} year(s)</div>
              <div>Department: {department}</div>
            </li>
          )
        })}
      </ul>
    </div>
  )
}

export default App
```

Now if you run the application, and select a department, you should see the employees only from that department.

## Filtering multiple values

If you need to add another filter, you can store the filter in a different state and run an [useEffect hook](https://www.codingdeft.com/posts/react-useeffect-hook/), whenever the filer changes.

```jsx
import { useEffect, useState } from "react"

const employees = [
  //..
]

function App() {
  const [filteredEmployees, setFilteredEmployees] = useState(employees)
  const [department, setDepartment] = useState()
  const [experience, setExperience] = useState()

  // Using Set to filter unique values
  const departments = Array.from(
    new Set(employees.map(employee => employee.department))
  )

  useEffect(() => {
    setFilteredEmployees(
      employees.filter(employee => {
        return (
          (!department || department === employee.department) &&
          (!experience ||
            (experience === "LESS_THAN_10"
              ? employee.experience < 10
              : employee.experience >= 10))
        )
      })
    )
  }, [department, experience])

  return (
    <div className="App">
      <select onChange={e => setDepartment(e.target.value)}>
        <option value="" disabled default selected>
          Select department
        </option>

        {departments.map(department => {
          return <option key={department}>{department}</option>
        })}
      </select>
      <div className="experience_filter">
        <button
          className={`${experience === "LESS_THAN_10" ? "selected" : ""}`}
          onClick={() => setExperience("LESS_THAN_10")}
        >
          Less than 10 years
        </button>
        <button
          className={`${experience === "10_PLUS" ? "selected" : ""}`}
          onClick={() => setExperience("10_PLUS")}
        >
          10+ years
        </button>
      </div>
      <ul>
        {filteredEmployees.map(employee => {
          const { name, experience, department, id } = employee
          return (
            <li key={id}>
              <div>
                Name: <strong>{name}</strong>
              </div>
              <div>Experience: {experience} year(s)</div>
              <div>Department: {department}</div>
            </li>
          )
        })}
        {filteredEmployees.length === 0 && (
          <div>No employees matching the filter</div>
        )}
      </ul>
    </div>
  )
}

export default App
```

In the above code, we have added an additional filter based on experience.
Each time the user changes a filter, we are saving the filter to its corresponding state. Also, we are running useEffect each time the filter changes.

Inside the useEffect, we are checking if the department filter and experience filter is applied. We have a not check (`!department` and `!experience`), so that we can apply the filter only if that particular filter is selected.

## Clearing all filters

Finally, let's add a clear filter button, to clear all the filters:

```jsx
import { useEffect, useState } from "react"

const employees = [
  //..
]

function App() {
  const [filteredEmployees, setFilteredEmployees] = useState(employees)
  const [department, setDepartment] = useState()
  const [experience, setExperience] = useState()

  // Using Set to filter unique values
  const departments = Array.from(
    new Set(employees.map(employee => employee.department))
  )

  useEffect(() => {
    setFilteredEmployees(
      employees.filter(employee => {
        return (
          (!department || department === employee.department) &&
          (!experience ||
            (experience === "LESS_THAN_10"
              ? employee.experience < 10
              : employee.experience >= 10))
        )
      })
    )
  }, [department, experience])

  const clearFilters = () => {
    setDepartment()
    setExperience()
  }

  return (
    <div className="App">
      <select onChange={e => setDepartment(e.target.value)}>
        <option value="" disabled default selected>
          Select department
        </option>

        {departments.map(department => {
          return <option key={department}>{department}</option>
        })}
      </select>
      <div className="experience_filter">
        <button
          className={`${experience === "LESS_THAN_10" ? "selected" : ""}`}
          onClick={() => setExperience("LESS_THAN_10")}
        >
          Less than 10 years
        </button>
        <button
          className={`${experience === "10_PLUS" ? "selected" : ""}`}
          onClick={() => setExperience("10_PLUS")}
        >
          10+ years
        </button>
      </div>
      <button onClick={clearFilters}>Clear All filters</button>
      <ul>
        {filteredEmployees.map(employee => {
          const { name, experience, department, id } = employee
          return (
            <li key={id}>
              <div>
                Name: <strong>{name}</strong>
              </div>
              <div>Experience: {experience} year(s)</div>
              <div>Department: {department}</div>
            </li>
          )
        })}
        {filteredEmployees.length === 0 && (
          <div>No employees matching the filter</div>
        )}
      </ul>
    </div>
  )
}

export default App
```

## Source code and demo

You can download the source code [here](https://github.com/collegewap/react-filter-object-array.git) and view a demo [here](https://react-filter-object-array.vercel.app/).