How to use Array.filter to narrow down a list in React
Tags: react, beginners, arrays, webdev
Published: 2022-12-17 15:59:18

How do you filter lists of data based on some user input? This is easily done using the `Array.filter` method!

How Does `Array.filter` Work? 🤔
--------------------------------

The `Array.filter` method takes an array of items and returns a completely new array that only contains the elements from the original array that match certain conditions. The original array is not changed at all, making this a non-destructive operation.

Now we're going to look at the most important concept in this post: The conditions are provided by a predicate functionwhich might sound complicated, but is really just a fancy name for a function that returns either `true` or `false` based on certain conditions.

A predicate function is is provided as an argument to the `Array.filter` method.. If it returns `true` then the element will be in the returned array. If it returns `false` then the element will not be included in the returned array.

For example applying the predicate function `isPurple` to this array of shapes will result in a new array containing only the purple shapes from the original array:

![](https://scrimba.com/articles/content/images/2022/11/array-filter-example-1-1.png)

In the next example, applying the predicate function `isRound` to the array of shapes will result in a new array containing all the circles that were in the original array:

![](https://scrimba.com/articles/content/images/2022/11/array-filter-example-2-1.png)

Let's have a quick look at some code that will filter the following array of numbers:

Simplest possible filter example
--------------------------------

```
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

```

First of all, we need a predicate function. The following `isEven` function will return true if the number provided as an argument is even and false otherwise:

```
const isEven = number => number % 2 === 0
```

Now you know what `isEven` does, can you predict what the following code will return?

```
numbers.filter(isEven)

```

If you guessed that only the even numbers in the `numbers` array will be returned then congratulations, you were absolutely right:

```
[2, 4, 6, 8, 10]

```

Now let's look at a more real-world example in React that takes an array of exam results and filters them to find out which marks got a distinction and which failed.

Filter list in React
--------------------

First of all, we need to create a variable to store the exam results (these are just a list of random marks out of 100, feel free to make your own up):

```

const testResults = [56, 68, 100, 75, 85, 76, 45, 83, 38, 45, 67]

```

Next we need to create predicate functions for filtering out the marks that failed the exam and the marks that get a distinction. Getting less than 40% is a fail and getting 85% or more is a distinction. Each predicate function accepts the mark as the only parameter and returns the Boolean result of checking if the mark is less than 40 or greater than or equal to 85:

```
const fail = mark => mark < 40
const distinction = mark => mark >= 85

```

To display a list of all the marks we will use the following `App` component:

```
const App = ({results}) =>
  <div>
    <h1>Distinctions</h1>
    <div>{results.filter(distinction).join(",")}</div>
    <h1>Fails</h1>
    <div>{results.filter(fail).join(",")}</div>
  </div>

```

The important lines here are where we use `Array.filter` to only display the marks that have achieved the distinction and fail marks:

```
<div>{results.filter(distinction).join(",")}</div>
<div>{results.filter(fail).join(",")}</div>

```

As you can see, it's as simple as calling the `filter` method with the relevant predicate function to filter the `results` array and leave just the results we want. We also use the `join` method to display a string with each result joined by a comma. In the later examples we will use `[Array.map](<http://Array.map>)` to add some JSX to each element.

You can see this example on [CodePen](https://codepen.io/daz4126/pen/YzvyrEX).

Note that this technique should only be used if you are filtering a list of data dynamically based on user input, otherwise you should really apply the filter at the point when you actually get the data from the database or API as this will save you having to fetch large amounts of data that you're not actually going to use.

Filtering With Hooks
--------------------

Next we're going to expand on the previous example by using React's hooks to add some buttons to filter the test results.

This example is quite similar to the last one, but with a few changes that we'll discuss:

```
const testResults = [56, 68, 100, 75, 85, 76, 45, 83, 38, 45, 67]

const App = ({results}) => {
  const [level, setLevel] = useState("distinction")
  const checkResults = mark => level === "distinction" ? mark > 85 : mark < 40
  return <div>
    <button onClick={e => setLevel("distinction")}>Distinctions</button>
    <button onClick={e => setLevel("fail")}>Fails</button>
    <h1>Test Marks</h1>
    <div>{results.join(",")}</div>
    <h1>{level === "distinction" ? "Distinctions" : "Fails"}</h1>
    <div>{results.filter(checkResults).join(",")}</div>
    </div>
}

ReactDOM.render(<App results={testResults} />, document.getElementById("root"))

```

First of all, we use the `useState` hook to set a variable called `level` and give it a default value of "distinction":

```
const [level, setLevel] = useState("distinction")
```

This will be used to track whether or not we want look at the distinction or fail results.

Next we create the predicate function that we'll use to filter the results:

```
const checkResults = mark => level === "distinction" ? mark > 85 : mark < 40

```

This is a combination of the two predicate functions we used last time. We use a ternary operator to check if the `leve`l is set to "distinction" and if it is, we filter marks that are over 85, if not then we must be looking for "fail" marks so filter marks below 40.

In the JSX that is returned, we need to add a couple of buttons

```
<button onClick={e => setLevel("distinction")}>Distinctions</button>
<button onClick={e => setLevel("fail")}>Fails</button>

```

These both use the `setLevel` method to update the value of `level` to "distinction" or "fail" depending on which button is pressed.

Next we just display all the results in a comma-separated list:

```
<h1>Test Marks</h1>
<div>{results.join(",")}</div>

```

Then we display the filtered results and use a ternary operator to create a heading that says "Distinctions" or "Fails" based on the value of `level`:

```
<h1>{level === "distinction" ? "Distinctions" : "Fails"}</h1>
<div>{results.filter(checkResults).join(",")}</div>

```

You can see this on [CodePen](https://codepen.io/daz4126/pen/LYrezKJ):

Filtering Strings As You Type
-----------------------------

Now let's take a look at how you might filter strings. A common feature of large lists of data is to allow users to search the list and filter it as they type. Let's use `Array.filter` to implement this functionality.

The code to do this can be seen below:

```
const App = () => {
  const languages = ["JavaScript","Python","C","C++","C#","Swift","Java","Ruby","Haskell"]
  const [searchString, setSearchString] = useState()
  const startsWith = str => word => str ? word.slice(0,str.length).toLowerCase() === str.toLowerCase() : true

  return <div>
           <input onChange={e => setSearchString(e.target.value)} />
           <ul>
            {languages.filter(startsWith(searchString)).map(lang => <li>{lang}</li>)}
           </ul>
         </div>
}

```

Let's break down how this works.

First of all, we create a list of programming languages that we'll be displaying and filtering (feel free to add any more!):

Next we use the `useState` hook to store a variable called `searchString`. This will be the string that the user enters and is used to filter the languages by only displaying languages include that string::

```
const [searchString, setSearchString] = useState()
```

Then we need a predicate function to do the filtering:

```
const contains = str => word => str ? word.toLowerCase().includes(str.toLowerCase()) : true

```

Here we use the includes method to check if the `searchString` is included in each word. We convert both strings to lowercase so that we don't need to worry about the case matching. If the `searchString` is in included in the string then we'll keep the string in the new array, if not, it will be filtered out. If there isn't a search string, then this predicate function will just return true, meaning that every element in the original array will remain.

Last of all, we just need to return the JSX for the view:

```
return <div>
           <input onChange={e => setSearchString(e.target.value)} />
           <div>
            {languages.filter(contains(searchString)).join(",")}
           </div>
        </div>

```

Here we use an input element with an `onChange` event listener that will fire every time anything is entered into the input box. When this happens, the value of the `searchString` is updated to whatever is inside the `input` element and this is passed to the `contains` function to create a predicate function that will filter the array.

The example can be seen on [CodePen](https://codepen.io/daz4126/pen/yLEOPjQ), have a play around with it to see how it works!

Filtering Objects
-----------------

As we know, most data that we'll end up using will be stored as objects. These can be filtered just as easily as numbers and strings using predicate functions. Let's create an array of objects to filter:

```
const people = [{
        emoji: "🤶",
        hat: true,
        glasses: true
    },
    {
        emoji: "🤴",
        hat: true,
        glasses: false
    },
    {
        emoji: "👩‍🍳",
        hat: true,
        glasses: false
    },
    {
        emoji: "👷‍♀️",
        hat: true,
        glasses: false
    },
    {
        emoji: "👴",
        hat: false,
        glasses: true
    },
    {
        emoji: "👵",
        hat: false,
        glasses: true
    },
    {
        emoji: "👩‍🔬",
        hat: false,
        glasses: true
    },
    {
        emoji: "👦",
        hat: false,
        glasses: false
    },
    {
        emoji: "👩‍🔧",
        hat: false,
        glasses: false
    },
    {
        emoji: "👩‍🦰",
        hat: false,
        glasses: false
    }
]
```

This array contains a number of objects that contain an `emoji` property and two other Boolean properties called `hat` and `glasses` that describe whether or not the emoji wears a hat and glasses respectively.

First of all, we'll add a filter to display only the emojis that are wearing hats.

We'll use the `setState` hook to do this:

```
const [hat, setHat] = useState(true)
```

For example, if `hat` is true, then we only want to display the emojis that are wearing a hat.

In order to allow the user to change the state, we'll add a button that changes the value of the `hat` variable:

```
<button onClick={e => setHat(!hat)} className={hat ? "active" : null}>Hat</button>

```

Clicking on these buttons will flip the Boolean value of  `hat`, so if it is `true` it will be set to `false` and vice versa.

Last of all, we just need to apply `Array.filter` in order to filter based on the value of  `hat` :

```
<ul>
  {people.filter(person => person.hat === hat).map(person => <li>{person.emoji}</li>)}
</ul>

```

Note that this example also uses `[Array.map](<http://Array.map>)` to make sure that we only display the "emoji" property of the object as an HTML list-item. You can [read more about how to do this here](https://scrimba.com/articles/react-list-array-with-map-function/).

Clicking on the button will alternate the display between showing a filtered list of emojis wearing hats and not wearing hats. 

You can see this example on [CodePen](https://codepen.io/daz4126/pen/rNKppaP).

Multiple Filters
================

For our last example, we're going to expand on the previous example to demonstrate how to filter multiple items at once. We'll do this by adding a second button that will add a filter based on whether the emojis are wearing glasses or not. This was another Boolean property that was in each object.

First of all we need to use the `setState` hook to add another variable to track the state of whether the emoji has glasses or not. This follows the same pattern we used earlier for whether or not they were wearing a hat:

```
const [glasses, setGlasses] = useState(true)
```

Then we need to add a button that will toggle the Boolean value of `glasses`:

```
<button onClick={e => setGlasses(!glasses)} className={glasses ? "active" : null}>Glasses</button>

```

Now we chain two filters one after the other to first check if the emoji is wearing a hat and then to check if they are wearing glasses or not:

```
<ul>
   {people.filter(person => person.hat === hat).filter(person => person.glasses === glasses).map(person => <li>{person.emoji}</li>)}
</ul>

```

This filter starts and ends in the same way as earlier, but we have chained the following filter into the middle of the expression:

```
filter(person => person.glasses === glasses)

```

This means that first of all we will filter the list of objects based on the value of  `hat`then we filter this new list based on the value of `glasses`. The result is a list that matches both the states of the `hat` and `glasses` variables.

This process of chaining multiple filters together works - if you make `hat` and `glasses` both true, then you will only see any emojis that are wearing a hat and glasses. This method can become inefficient however, especially with large amounts of data and even more Boolean conditions. The reason for this is that the original list needs to be iterated over for every `filter` method. This means that you might have to go through a large list of objects multiple times, which could become inefficient and slow things down.

A much better way to achieve the same result is to use a single `filter` with the logical AND operator, `&&`. This will apply multiple predicates in a single filter. The example above can be rewritten more efficiently in the following way:

```
<ul>
  {people.filter(person => person.hat === hat && person.glasses === glasses).map(person => <li>{person.emoji}</li>)}
</ul>

```

This will still work in the same way, but only pass over the original array once to filter and then one more time to map each object to a string of HTML - much more efficient!

You can see this on [CodePen](https://codepen.io/daz4126/pen/zYaqLaV).

The Verdict
-----------

The `Array.filter` method can be used to filter values in a list based on a given rule. This lets you filter data dynamically based on user input. In this post, we've looked at the different ways to use this method effectively with numbers, strings and objects as well as how to apply multiple filters all at once. I hope you've found this useful and can start using filters in your code today!