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:
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:
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 an interactive code example below:
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 an interactive code example below:
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 in the CodePen below, 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.
Clicking on the button will alternate the display between showing a filtered list of emojis wearing hats and not wearing hats. Here’s an interactive CodePen that you can have a play around with:
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 an interactive CodePen example below:
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!