Get the 2024 Yearly Goals and Progress Tracker Notion Template for FREE!

How to Create React Search Component Using React Hooks

Posted on: Jun 21, 2023

9 mins read

Originally published at www.turing.com

How to Create React Search Component Using React Hooks

A Search Component is a UI element in a software application that allows a user to search for specific information or data. The component typically includes an input field where the user can enter a search query and a button to initiate the search. The search results are displayed to the user in a suitable format, such as a list or table.

The purpose of a Search Component is to provide a simple and efficient way for the user to find the information they are looking for within the application. A well-designed Search Component can significantly improve the user experience and make it easier for users to find what they want.

This article will discuss building a simple React Search Component using some React Hooks like useState and useEffect.

What are React Hooks?

React Hooks are functions in React that allow developers to add state and side effects to functional components. They were introduced in React 16.8 as an alternative to class components for adding state and logic. React Hooks simplify code and eases the process of building reusable and composable components. This include built-in hooks like useState, useEffect, and useContext, as well as the ability to create custom hooks. You can learn more about it from the React documentation website.

React Hooks are a good choice for creating a search component in React because they allow for reusable, simple, optimized, and easy-to-test components. They simplify the code, make it easier to understand, and only update what has changed for improved performance. These benefits make React Hooks a good choice for building efficient and effective search components in React. We will use the two most common hooks; useState() and useEffect().

Setting up the project

Create a React app called react search component by running the command npx create-react-app react-search-component, then install the axios package by running npm install axios or yarn add axios. After that, open up the app in your preferred code editor, and run the command npm dev or yarn dev to view the app in your browser.

Building the search component

We will build a one-page app that displays facts about different countries. We have created a mock API using the tool mockAPI and populated it with country facts obtained from Facts.net. There will also be a search bar, where one can enter a search query. The country facts that contain the search query will be displayed in real-time when the user enters the search query.

Let us build and style the page. Going into the App.js file, write the following code:

jsx
import React from "react";
import "./App.css";
const App = () => {
return (
<div className="App">
<header className="header">
<h1 className="page-title">Random Country Facts</h1>
<div className="form-input-group">
<label className="search-input-label" htmlFor="search">
<input
className="search-input"
type="search"
name="search"
id="search"
placeholder="Search..."
required
/>
</label>
</div>
</header>
<main>
<section className="cards-wrapper">
<article className="card" key="index">
<h2 className="short-fact">Title</h2>
<p className="long-fact">
Lorem, ipsum dolor sit amet consectetur adipisicing elit.
</p>
<p className="country-name">Country name</p>
</article>
<article className="card" key="index">
<h2 className="short-fact">Title</h2>
<p className="long-fact">
Lorem, ipsum dolor sit amet consectetur adipisicing elit.
</p>
<p className="country-name">Country name</p>
</article>
</section>
</main>
</div>
);
};
export default App;

From the code above, we have a header element containing our project's title and search input. We also have a main element containing an article element card that contains the dummy text, which will display the facts fetched later. Let us style them by adding the following code to our App.css file.

css
* {
box-sizing: border-box;
}
html,
body {
overflow-x: hidden;
}
body {
padding: 0 30px;
color: #434341;
max-width: 1400px;
margin: auto;
}
/* header */
.header {
padding: 20px 0;
text-align: center;
}
.page-title {
margin: 0 0 20px;
}
.form-input-group {
display: flex;
width: 100%;
max-width: 400px;
margin: auto;
}
.search-input-label {
border-radius: 5px;
flex-grow: 1;
}
.search-input {
width: 100%;
border: 1px solid #ddd;
padding: 5px 10px;
border-radius: 5px;
}
.search-input:focus {
outline: #434341;
}
.search-button {
padding: 5px 10px;
border-radius: 0 5px 5px 0;
border: 1px solid #ddd;
background-color: #eee;
}
/* cards */
.cards-wrapper {
display: grid;
gap: 20px;
grid-template-columns: repeat(3, 1fr);
margin: 40px 0 80px;
}
@media screen and (max-width: 960px) {
.cards-wrapper {
grid-template-columns: repeat(2, 1fr);
}
}
@media screen and (max-width: 786px) {
.cards-wrapper {
grid-template-columns: repeat(1, 1fr);
}
}
.card {
border: 1px solid #ddd;
border-radius: 5px;
padding: 5px 20px;
box-shadow: 4px 4px 4px 0px #eee;
}
.country-name {
border: 2px solid #eee;
border-radius: 5px;
width: max-content;
padding: 5px;
}

Let us view the changes in the browser. alt_text

This looks great. Now let us fetch our data and display it on the page. Returning to our App.js, we import axios from the axios package we installed earlier to fetch our data. We also import the React hooks from React, useEffect, and UseState.

jsx
import React, { useEffect, useState } from "react";
import axios from "axios";

The useState hook allows components to have state variables, which can change over time and trigger re-renders without using class components, while the useEffect hook allows components to perform side effects, such as updating the component's state or interacting with APIs, in response to changes in component's props or state.

We create two states called isLoading and FactsFata using the useState hook. The isLoading variable is a boolean we use to condition what we render on the screen. The factsData is an empty array that will hold the data we fetch. And while we fetch our data, a loading message will be displayed to the user until our data has been fetched and is ready to be displayed.

jsx
const [isloading, setIsloading] = useState(true);
const [FactsData, setFactsData] = useState([]);

Next, we write the function to fetch and store our data.

jsx
useEffect(() => {
axios
.get(`https://63db4515b8e69785e47e7435.mockAPI.io/country`)
.then((response) => {
setFactsData(response.data);
setIsloading(false);
})
.catch((err) => {
console.log(err);
});
}, []);

Below our states, we have written our function within a useEffect hook. This function fetches data from the mock API created and stores it in the fetchData state. After that, it sets the IsLoading state from true to false. Now, let us output the data to the user. Replace the current code within the main element with the following;

jsx
<main>
{isloading ? (
<p className="message">loading...</p>
) : (
<section className="cards-wrapper">
{factsData.map((data) => (
<article className="card" key="index">
<h2 className="short-fact">{data.shortFact}</h2>
<p className="long-fact">{data.longFact}</p>
<p className="country-name">{data.country}</p>
</article>
))}
</section>
)}
</main>

We created a ternary operator to conditionally render different UI elements depending on the value of the isloading variable. If isloading is true, it displays a p element with the text "loading...". If isloading is false, it maps over the factsData array and creates a card for each item, displaying a short fact, a long fact, and a country name. Let us view it in our browser.

alt_text

Next, let us get the search query from the search bar and store it in a state.

jsx
const [searchInput, setSearchInput] = useState("");
<input
className="search-input"
type="search"
name="search"
id="search"
placeholder="Search..."
value={searchInput}
onChange={(e) => {
setSearchInput(e.target.value);
}}
required
/>;

From the code above, we created a state called searchInput, initially set to an empty string, and then the value of our input element was set to the searchInput state variable. We also added an onChange attribute to the input element, which sets the searchInput state variable to the query the user enters. If you log the searchInput state variable to the console and enter a search query, you will see the value output as you type in the query.

Let us now show specific results based on the user's search query.

We create a state called filteredResults to store our filtered result with an empty array as its initial value.

jsx
const [filteredResults, setFilteredResults] = useState([]);

We also create a react search bar function within another useEffect hook for our search bar component.

jsx
useEffect(() => {
const filteredData = factsData.filter((fact) => {
return Object.values(fact)
.join("")
.toLowerCase()
.includes(searchInput.toLowerCase());
});
setFilteredResults(filteredData);
}, [factsData, searchInput]);

This React search function updates the state of filteredResults based on the changes in the variables factsData and searchInput, which we passed in as a second argument to the useEffect hook telling React to run this effect only when either of these values changes.

It filters the factsData array based on whether the string representation of the fact object's values contains the lowercase value of searchInput. The filtered data is then stored in filteredData and set as the value of filteredResults using setFilteredResults.

Next we go back into our main element and include another ternary operator within the section element to render either the fetched data or filtered result.

jsx
<main>
{isloading ? (
<p className="message">loading...</p>
) : (
<section className="cards-wrapper">
{filteredResults.length === 0
? factsData.map((data) => (
<article className="card" key="index">
<h2 className="short-fact">{data.shortFact}</h2>
<p className="long-fact">{data.longFact}</p>
<p className="country-name">{data.country}</p>
</article>
))
: filteredResults.map((data) => (
<article className="card" key="index">
<h2 className="short-fact">{data.shortFact}</h2>
<p className="long-fact">{data.longFact}</p>
<p className="country-name">{data.country}</p>
</article>
))}
</section>
)}
</main>

This second ternary operator checks the length of the filteredResults array. If it is equal to 0, it maps over the factsData array, and for each item in the array, it creates a card for each fact.

If the length of the filteredResults array is not equal to 0, then it maps over the filteredResults array and creates a card for each item in the same way described above.

alt_text

Our final code should look like this.

jsx
import React, { useEffect, useState } from "react";
import "./App.css";
import axios from "axios";
const App = () => {
const [isloading, setIsloading] = useState(true);
const [factsData, setFactsData] = useState([]);
const [searchInput, setSearchInput] = useState("");
const [filteredResults, setFilteredResults] = useState([]);
useEffect(() => {
axios
.get(`https://63db4515b8e69785e47e7435.mockAPI.io/country`)
.then((response) => {
setFactsData(response.data);
setIsloading(false);
})
.catch((err) => {
console.log(err);
});
}, []);
useEffect(() => {
const filteredData = factsData.filter((fact) => {
return Object.values(fact)
.join("")
.toLowerCase()
.includes(searchInput.toLowerCase());
});
setFilteredResults(filteredData);
}, [factsData, searchInput]);
return (
<div className="App">
<header className="header">
<h1 className="page-title">Random Country Facts</h1>
<form className="form-input-group">
<label className="search-input-label" htmlFor="search">
<input
className="search-input"
type="search"
name="search"
id="search"
placeholder="Search..."
value={searchInput}
onChange={(e) => {
setSearchInput(e.target.value);
}}
required
/>
</label>
</form>
</header>
<main>
{isloading ? (
<p className="message">loading...</p>
) : (
<section className="cards-wrapper">
{filteredResults.length === 0
? factsData.map((data) => (
<article className="card" key="index">
<h2 className="short-fact">{data.shortFact}</h2>
<p className="long-fact">{data.longFact}</p>
<p className="country-name">{data.country}</p>
</article>
))
: filteredResults.map((data) => (
<article className="card" key="index">
<h2 className="short-fact">{data.shortFact}</h2>
<p className="long-fact">{data.longFact}</p>
<p className="country-name">{data.country}</p>
</article>
))}
</section>
)}
</main>
</div>
);
};
export default App;

Conclusion

That's it on building a Search Component in React using some React Hooks. This can be further customized by adding a button to the react search bar component and displaying the result only when the button is clicked.

You can find the source code on GitHub and interact with the app.

Frequently Asked Questions

1. How do I create a search component in React?

You can create a search component in React by using a text input field and a button to trigger the search functionality. The text input field can capture the user's search query, and the button can be clicked to initiate the search.

2. How do I get the search input value in React?

You can get the search input value in React by using the "onChange" event listener on the text input field. This will allow you to capture the user's input as they type, and update the search query accordingly.

3. How do I create a dynamic search box in React?

You can create a dynamic search box in React by using the "useState" hook to manage the state of the search query. You can then pass the search query as a prop to your search component, and use it to filter your search results dynamically as the user types.

Connect With Me

Follow me on X(Twitter), and LinkedIn to stay updated with my latest content.

If you like my notes and want to support me, you can sponsor me on GitHub Sponsor, or you can buy me a virtual ice cream on ByMeACoffee or Selar. I would really appreciate it. 🙏

For other ways to support me, visit my Sponsorship page or Affiliate Links page.

Subscribe to my newsletter 💌

Never miss a beat! Stay updated with my latest tech tutorials, code snippets, how-to guides, productivity tips, personal projects and experiences, and more! 💻📚✨