Skip to content
react

How to Search and Filter an array in React

Dec 6, 2022Abhishek EH7 Min Read
How to Search and Filter an array in React

You might have come across many applications where you can search a list of items or a long dropdown list within which you can search for the item easily. In this tutorial, we will see how to achieve this in React.

If you are looking for filtering array of objects, you can refer this article.

We will be implementing the following:

  • Filter a list of numbers based on if they are even or odd.
  • Search from a list of names.
  • A dropdown to choose a primary skill, with a search option.

Setting up the project

Create a new react app using the following command:

1npx create-react-app react-filter

Let's add some styling to our application in index.css:

index.css
1body {
2 margin: 10px auto;
3 max-width: 700px;
4}
5
6body ::-webkit-scrollbar-track {
7 background: rgba(0, 0, 0, 0.1);
8 border-radius: 0;
9}
10body ::-webkit-scrollbar-thumb {
11 cursor: pointer;
12 border-radius: 5px;
13 background: rgba(0, 0, 0, 0.25);
14 -webkit-transition: color 0.2s ease;
15 transition: color 0.2s ease;
16}
17body ::-webkit-scrollbar {
18 -webkit-appearance: none;
19 width: 10px;
20 height: 10px;
21}
22label {
23 margin-left: 5px;
24 margin-right: 5px;
25}
26.dropdown-search {
27 border: solid 1px black;
28 display: inline-block;
29 padding: 1px 2px;
30 border-radius: 2px;
31 cursor: pointer;
32 width: 180px;
33 font-size: 13.3333px;
34}
35.default {
36 border: solid 1px grey;
37 color: grey;
38}
39.dropdown-input {
40 width: 180px;
41 display: block;
42}
43
44.dropdown-list ul {
45 border: 1px solid gray;
46 margin: 0;
47 padding: 0;
48 display: inline-block;
49 width: 186px;
50 max-height: 200px;
51 overflow-y: scroll;
52 border-top: none;
53}
54.dropdown-list li {
55 list-style: none;
56 padding: 5px;
57 cursor: pointer;
58}
59
60.dropdown-list li:hover {
61 background: rgba(0, 0, 0, 0.03);
62 font-weight: bold;
63}
64.dropdown-wrapper {
65 display: inline-block;
66}
67
68.dropdown-list li.no-result {
69 color: grey;
70}
71
72.dropdown-list li.no-result:hover {
73 font-weight: normal;
74}

Filtering numbers

Update App.js with the following code:

App.js
1import { useState } from "react"
2
3let numbers = [64, 84, 22, 32, 83, 65, 51, 26, 23, 56]
4function App() {
5 const [filteredNumbers, setFilteredNumbers] = useState(numbers)
6
7 return (
8 <div className="App">
9 <h2>Number filtering</h2>
10 <input type="radio" name="evenOrOdd" id="even" value="even" />
11 <label htmlFor="even">Even</label>
12 <input type="radio" name="evenOrOdd" id="odd" value="odd" />
13 <label htmlFor="odd">Odd</label>
14 <ul>
15 {filteredNumbers.map(number => {
16 return <li key={number}>{number} </li>
17 })}
18 </ul>
19 </div>
20 )
21}
22
23export default App

In the above code, we have added a couple of radio buttons to choose between odd and even numbers and we have a state called filteredNumbers, which we are initializing with the list of numbers. We are looping through the numbers and displaying them in a list.

Let's add the filtering logic to our code:

App.js
1import { useState } from "react"
2
3let numbers = [64, 84, 22, 32, 83, 65, 51, 26, 23, 56]
4function App() {
5 const [filteredNumbers, setFilteredNumbers] = useState(numbers)
6
7 const radioChangeHandler = e => {
8 const value = e.target.value
9 if (value === "even") {
10 setFilteredNumbers(
11 numbers.filter(number => {
12 if (number % 2 === 0) {
13 return true
14 }
15 return false
16 })
17 )
18 } else {
19 setFilteredNumbers(
20 numbers.filter(number => {
21 if (number % 2 !== 0) {
22 return true
23 }
24 return false
25 })
26 )
27 }
28 }
29
30 return (
31 <div className="App">
32 <h2>Number filtering</h2>
33 <input
34 type="radio"
35 name="evenOrOdd"
36 id="even"
37 value="even"
38 onChange={radioChangeHandler}
39 />
40 <label htmlFor="even">Even</label>
41 <input
42 type="radio"
43 name="evenOrOdd"
44 id="odd"
45 value="odd"
46 onChange={radioChangeHandler}
47 />
48 <label htmlFor="odd">Odd</label>
49 <ul>
50 {filteredNumbers.map(number => {
51 return <li key={number}>{number} </li>
52 })}
53 </ul>
54 </div>
55 )
56}
57
58export default App

Here, we have written a function called radioChangeHandler, in which we check if the selected radio box value is "even". If it is "even", then we call the JavaScript filter function and use the modulus operator (%) to determine if the number is even. The array returned (array of even numbers) from the filter function is then set to the filteredNumbers state. A similar logic is written in the else condition for odd numbers.

If you run the application now, you should be able to filter the odd and even numbers:

number filter

Searching a list of names

Let's display a search box and a list of names:

App.js
1import { useState } from "react"
2
3let names = [
4 "Shea",
5 "Ewing",
6 "Yang",
7 "Mcintosh",
8 "Castillo",
9 "Cunningham",
10 "Johnston",
11 "Mckay",
12 "Roberson",
13 "Perez",
14 "Dudley",
15 "Wood",
16]
17function App() {
18 const [searchValue, setSearchValue] = useState("")
19
20 return (
21 <div className="App">
22 <h2>Search filtering</h2>
23 <input
24 type="text"
25 name="search"
26 value={searchValue}
27 onChange={e => setSearchValue(e.target.value)}
28 />
29 <ul>
30 {names.map(name => {
31 return <li key={name}>{name} </li>
32 })}
33 </ul>
34 </div>
35 )
36}
37
38export default App

We have the value of the input box stored in the local state: searchValue. Let's use it to filter the list:

App.js
1import { useState } from "react"
2
3let names = [
4 "Shea",
5 "Ewing",
6 "Yang",
7 "Mcintosh",
8 "Castillo",
9 "Cunningham",
10 "Johnston",
11 "Mckay",
12 "Roberson",
13 "Perez",
14 "Dudley",
15 "Wood",
16]
17function App() {
18 const [searchValue, setSearchValue] = useState("")
19
20 return (
21 <div className="App">
22 <h2>Search filtering</h2>
23 <input
24 type="text"
25 name="search"
26 value={searchValue}
27 onChange={e => setSearchValue(e.target.value)}
28 />
29 <ul>
30 {names
31 .filter(name => name.match(new RegExp(searchValue, "i")))
32 .map(name => {
33 return <li key={name}>{name} </li>
34 })}
35 </ul>
36 </div>
37 )
38}
39
40export default App

Here we are making a case insensitive match for the name.

If you run the application now, you should be able to search and filter the name:

name search

Filtering a dropdown list

Update the App.js with the following code:

App.js
1import { useEffect, useRef, useState } from "react"
2
3let skills = [
4 "Angular",
5 "CSS",
6 "Graphic Design",
7 "Ember",
8 "HTML",
9 "Information Architecture",
10 "JavaScript",
11 "Mechanical Engineering",
12 "Meteor",
13 "NodeJS",
14 "Plumbing",
15 "Python",
16 "Rails",
17 "React",
18 "Kitchen Repair",
19 "Ruby",
20 "UI Design",
21 "User Experience",
22]
23
24function App() {
25 const [selectedSkill, setSelectedSkill] = useState("")
26 const [dropdownSearchValue, setDropdownSearchValue] = useState("")
27 const [editMode, setEditMode] = useState(false)
28 const dropdownRef = useRef()
29
30 /**
31 * Close the dropdown when clicked outside
32 * Refer https://www.codingdeft.com/posts/react-on-click-outside/ for details
33 */
34 useEffect(() => {
35 const checkIfClickedOutside = e => {
36 // If the menu is open and the clicked target is not within the menu,
37 // then close the menu
38 if (
39 editMode &&
40 dropdownRef.current &&
41 !dropdownRef.current.contains(e.target)
42 ) {
43 setEditMode(false)
44 }
45 }
46 document.addEventListener("mousedown", checkIfClickedOutside)
47 return () => {
48 // Cleanup the event listener
49 document.removeEventListener("mousedown", checkIfClickedOutside)
50 }
51 }, [editMode])
52
53 const skillSelectionHandler = skill => {
54 setSelectedSkill(skill)
55 setDropdownSearchValue("")
56 setEditMode(false)
57 }
58
59 const filteredSkills = skills.filter(skill =>
60 skill.match(new RegExp(dropdownSearchValue, "i"))
61 )
62
63 return (
64 <div className="App">
65 <h2>Dropdown filtering</h2>
66
67 {editMode ? (
68 // display the dropdown when the input us focused
69 <div ref={dropdownRef} className="dropdown-wrapper">
70 <input
71 className="dropdown-input"
72 name="dropdown-input"
73 autoFocus
74 onChange={e => setDropdownSearchValue(e.target.value)}
75 value={dropdownSearchValue}
76 />
77 <div className="dropdown-list">
78 <ul>
79 {filteredSkills.map(skill => {
80 return (
81 <li key={skill} onClick={() => skillSelectionHandler(skill)}>
82 {skill}{" "}
83 </li>
84 )
85 })}
86 {filteredSkills.length === 0 && (
87 <li className="no-result">No results found</li>
88 )}
89 </ul>
90 </div>
91 </div>
92 ) : (
93 <input
94 // Grey out the text when "Select Primary skill" input hint is shown
95 className={`dropdown-search ${
96 !(dropdownSearchValue || selectedSkill) && "default"
97 }`}
98 onFocus={() => setEditMode(true)}
99 // Display the selected skill or "Select Primary skill" input hint
100 value={selectedSkill || "Select Primary skill"}
101 />
102 )}
103 </div>
104 )
105}
106
107export default App

In the above code:

  • We have an array of skills.
  • By default, editMode state will be set to false, and an input box with greyed out text "Select Primary skill" will be displayed.
  • When the user clicks/focuses on the text box, editMode will be set to true and a dropdown will be displayed with the list of skills.
  • When the user types something on the search box, dropdownSearchValue will be updated with the keyword. The skills will be filtered and set to filteredSkills and displayed.
  • We also have a useEffect hook to close the dropdown whenever the user clicks outside the dropdown. I have written a detailed article on handling outside click in React components earlier.
  • When the user clicks on any of the skills, we are setting it to selectedSkill state in the skillSelectionHandler function and closing the dropdown.

If you run the application now, you should be able to search and choose a skill:

dropdown search

Source code and demo

You can view a demo here and the complete source code here.

Do follow me on twitter where I post developer insights more often!

© 2024 CodingDeft.Com