How To Build A Search Bar Using React Hooks
GitHub: https://github.com/JoeG21/medium-ex/tree/master/react-searchbar/src
A search bar is such a simple feature that really elevate any application that you work on. While learning how to build a search bar from scratch, I found that most solutions use Class Components or render the whole application in one component. With our example I’m going to be using Functional Components and breaking down our application in multiple components.
For our example, we are going to be building this.
Whenever a user search for a name that she or he type in the search bar, it’s going to filter out the names. And if there’s no match then it’s going to give us “No Result”.
import { useEffect, useState } from 'react';import Search from './Search'
import UserContainer from './UserContainer'const App = () => {
return (
<div className='App'> <Search /> <br /> <UserContainer /> </div>
);
};export default App
This is going to be our boiler plate code, as you can see we have two components. A Search and UserContainer to break down and isolate those part of our application. If you don’t know useEffect or useState then you can check out my blogs about them!
useState: https://devjoe.medium.com/implementing-react-hooks-usestate-53e565669439
useEffect: https://devjoe.medium.com/implementing-react-hooks-useeffect-e27b7a81c74e
I’m going to be calling on a dummy API from https://jsonplaceholder.typicode.com/ to display the users’ names. First thing we have to do is to set state to an empty array to put all of our users’ data that we are fetching. Then setting our “users” state in the promise.
const [users, setUsers] = (() => {
return []
})useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/users') .then(res => res.json()) .then(json => setUsers(json));
}, [])
Then we can give the prop “users” to our UserContainer component and passing the current state.
const App = () => {
return (
<div className='App'> <Search /> <br /> <UserContainer users={users} /> </div>
);
};
Then in our UserContainer we are going to map over the prop and pass it into another component called UserCard. Giving it a unique key prop and user prop.
import UserCard form './UserCard'const UserContainer = (props) => {
return (
<div> {props.users.map (user => <UserCard key={user.id} user={user}
/>)} </div>
);};export default UserContainer
In our UserCard we are just displaying the names.
const UserCard = (props) => {
return (
<div> {props.user.name} </div>
);
};export default UserCard
At this point, our application should look like this. Just displaying some names that we are fetching from.
Now lets’ add some functionality to our search bar. First we are going to give it type of “text” and an event listener to pass in a callback function. The “e” that we are passing in our parameters for our “searchUser” function is an event object.
const Search = (props) => { return ( <div> <input onChange={e => props.searchUser(e)}
id="search-bar"
type="text"
placeholder="Search"
/> </div> );};export default Search
All this means that whenever a user type anything in our search bar, it’s going to the listening to every single event that happens. We can of course prove this by console logging the “e” by targeting it and displaying its value. But first we just have to create a state in our App component and setting it to an empty string in order to store our e value. And pass down the callback function in our Search component.
const [searchTerm, setSearchTerm] = useState(() => { return ""})const searchUser = (e) => { setSearchTerm(prevState => console.log(e.target.value))};return (
<div className='App'> <Search searchUser={searchUser}/> <br /> <UserContainer users={users} /> </div>
);
Now we need an array to store all of our users that we are filtering.
const [foundUsers, setFoundUsers] = useState(() => { return []})
After, let’s change what we are rendering in our UserContainer by using useEffect in order to have a side of effect.
useEffect(() => { setFoundUsers( users.filter( user => { return user.name.toLowerCase().includes(searchTerm.toLowerCase())} ))}, [searchTerm, users])
I’m filtering through all of the “users” name and for each “user” I’m going to lower case the name for caps sensitivity purposes and if the name includes the searchTerm values that the user typed then return it inside that empty array of foundUser.
Finally, let’s display it.
return (
<div className='App'> <Search searchUser={searchUser} /> <br /> {foundUsers.length !== 0 ? <UserContainer users={foundUsers} /> : foundUsers.length === 0 ? <h1> No Result </h1> : <UserContainer users={users} />} </div>
);
Using a ternary operator, let’s add some conditions. The first condition, if our foundUsers array is not empty then display all the names that are in the foundUsers array. The second condition, if foundUsers is empty (equal to zero) then display the string “No Result” because whatever the user’s input was did not match any of the users’ name in our user array. The third condition, is our default value because it does not have a condition to run therefor making it always true causing it to automatically run.
And that’s pretty much it! Thank for following along and you can of course check out my GitHub for the code!
GitHub: https://github.com/JoeG21/medium-ex/tree/master/react-searchbar/src