Telerik blogs
ReactT2 Dark_1200x303

Having a functional search integration will enhance the user interaction on your website. Let’s learn how to add a standard full-text search to your React web app.

Search integration enables you to find things easily on a web application. With search integration, you can look for an item/product without going through the stress of scrolling manually to find the specific item or product.

Search integration means the process of implementing a user search input on a web application to help query the searched value from a connected database.

Having a functional search integration will enhance the user interaction on your website. It will give users a better experience when navigating your web application.

This article includes a step-by-step guide to implementing search integration into a web application.

In this article, you will learn:

  • What search integration is
  • Types of search integration
  • What react-router-dom is
  • The best approach for implementing a standard search

Prerequisites

To understand this tutorial, you will need to have:

  • React v16 or newer
  • A basic understanding of React
  • A basic understanding of Node.js
  • A text editor

Types of Search Integration

There are two significant types of text search:

  • Full-text search: A full-text search is a form of searching that compares every word in the search request to every word in the database.
  • Partial text search: Partial text search is when you enter part of a query word, but the database still manages to find the whole word.

The most reliable text search is the full-text search. This search type gives you a better experience when looking for a product/item on a web application. This is the type we’ll focus on today.

Before diving into the code aspect of the post, there are some additional terms you need to know for performing a full-text search:

  • Routing: When you click an element (link, button) within an application, routing allows you to move between different portions of the web application. That makes the transition of pages seamless without having to reload or re-render the whole page.
  • React-router-dom: This is a React library for creating dynamic routing in a React web application using the react-router-dom package.

Let’s begin by setting up our project environment. First, create a project directory.

mkdir siApp

Next, initialize Yarn in the project directory.

yarn init

You will be asked some questions, and then it will automatically generate a package.json file that will contain the responses to the questions you answered earlier. See the basic structure below.

{
  "name": "your-app-name",
  "version": "1.0.0",
  "main": "index.js",
  "author": "sproff",
  "license": "MIT",
},

Note: If you don’t answer the required questions, it will automatically select a default response for you.

Now you can start installing your packages. But for this tutorial, I will be installing Express.js.

yarn add express

The package will be added to the dependencies inside your package.json file. See the structure below.

{
  "name": "your-app-name",
  "version": "1.0.0",
  "main": "index.js",
  "author": "sproff",
  "license": "MIT",
  "dependencies": {
    "express": "^4.17.1",
  },

As you can see, the Express package is now a dependency. Now, let’s create a Hello World app inside the index.js file.

const express = require("express")
const app = express()
const port = 9000

app.get("/", (req, res) => {
  res.send("Hello World!")
})

app.listen(port, () => {
  console.log(`Server is running on PORT:${port}`)
})

After setting up your index.js file, run node index.js in your terminal. Then, go to your browser and visit localhost:9000. You should see your message—“Hello World.”

Next, we need to set up the search controller inside your Node.js application. Create a folder inside your parent folder called controllers, then create a file inside called product.controller.js.

// product.controller.js
const searchProduct = async (req, res, next) => {
  try {
    const { q } = req.query;
    const products = await Product.find({ name: { $regex: q, $options: 'i' } });
  
    if (products.length < 1) throw new ErrorHandler(404, 'No product found');

    res.status(201).json({
      status: 'success',
      message: 'Product has been found successfully',
      products,
    });
  } catch (error) {
    next(error);
  }
};

Note: To set up a controller, you should have created a schema and other basic setups to enable your app to work.

In the code above, we started by declaring a try-catch statement and then assigned query params. Then we declared a variable that will contain a Mongoose attribute of find.

The find attribute tends to query the database whenever you input a particular letter/word. Then you validate your response by checking if the product is available or not by creating a conditional statement.

Next, we need to create a new React app with react-router-dom.

yarn create react-app my-app react-router-dom

Now, we need to set up the route. To set up your route, create a folder called routes and then create a file inside the folder called route.js.

// route.js
import React from "react";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";

export const Routes = () => {
  return (
    <Router>
      <Switch>
        <Route path="/search">
          <SearchResults />
        </Route>
        <Route exact path="/">
          <Home />
        </Route>
      </Switch>
    </Router>
  );
};

The code above contains the route that will handle the transition of your pages.

  • BrowseRouter can be renamed to any name, so it is renamed to Router to keep it short, which is also the standard naming convention.
  • Router serves as a parental div that will wrap all the routes; without the Router, your routes won’t work.
  • Switch does what its name implies—it allows you to navigate from one page to another.
  • Route is the primary tag that nests your component. It specifies the pages that should be rendered whenever you click a specific link. It takes some props called path and exact.

Next, we need to create a new file for search input. Navigate to your parent folder, create a subfolder called component, and then create the search input file using this command below.

touch SearchInput.jsx

Paste the following code into SearchInput.jsx.

// SearchInput.jsx
import React, { useState} from "react";
import { useHistory } from "react-router-dom";

export const SearchInput = () =>
{
  const [search, setSearch] = useState("");
  const history = useHistory();
  return (
    <div>
      <InputGroup>
       <Input
        onChange={(e) => {
        setSearch(e.target.value)
        }}
        type="search"
        placeholder="Search product"
       />
       <InputRightElement>
        <div>
          <button onClick={() => history.push(`/search?query=${search}`)} >Search</button>
        </div>
       </InputRightElement>
      </InputGroup>
    </div>
  )
}

A state is created in the code above to listen to your input; the setSearch handles the onChange event; and the search state handles the input rendering, which will be triggered when you click the search button.

The useHistory hook provides access to the history instance, which is used to navigate. The action executed inside the button tag means that you are listening for an onClick event that will trigger the history.push. This will push you to another route (/search) created earlier, then store your input inside the search state.

The search state will be passed as a query to the new route (/search) and then render the output based on the database results.

Next, create a new file for search results. Navigate to your parent folder, create a subfolder called pages, and then create the search input file using this command below.

touch SearchResults.jsx

Paste the following code into SearchResults.jsx.

// SearchResults.jsx
import React, { useEffect, useState } from "react";
import { Link, useLocation, useParams } from "react-router-dom";

export const SearchResults = () => {
  const [searchResults, setSearchResults] = useState([]);
  const [error, setError] = useState(false);
  const location = useLocation();
  const query = new URLSearchParams(location.search).get("query");
  const { slug } = useParams();
  useEffect(() => {
    const searchProduct = async () => {
      try {
        const { data } = await axios.get(`API_URL/search?q=${query}`); setSearchResults(data.products);
        } catch (error) {
         setError(error.response?.data?.message);
         }
        };
         searchProduct();
       }, []);

  return (
    <div>
      {searchResults.map((searchResult) => (
        <div
          key={searchResult.id}
          <p>{searchResult.name}</p>
        </div>
      ))}
    </div>
  )
}

Above, we created two React hooks which are the useState and the useEffect. Two different states have been created, which are the searchResults and error states.

The useState hook declares state variables to preserve some values between the function calls, and it returns a pair of values: the current state and a function that updates it. The useEffect hook helps in data fetching, while the searchResults state handles the data coming from a specific API. Lastly, the error state handles errors coming from the overall actions.

The useLocation hook returns the location object representing the current URL. It serves as a redirect to another page whenever you click on a component. The hook is then attached to the query variable where an event will trigger it.

The API URL is attached to a search query that will enable the stored user input to trigger the .find attribute in Mongoose, which was declared earlier. The setSearchResults state will listen to the results obtained from the API and then render it to the user using a map function by mapping through with the searchResults state.

Conclusion

Finally, we have created a functional search input with standard search results without any external library needed. We touched on the different types of text search, discussed what react-router-dom is, and highlighted a standard way to perform a full-text search.


Chinedu
About the Author

Chinedu Imoh

Chinedu is a tech enthusiast focused on full-stack JavaScript and Infrastructure engineering.

Related Posts

Comments

Comments are disabled in preview mode.