skip to Main Content

Problem Description:

I’m working on implementing a search bar in my React application. The search bar should show a list of suggestions when users type in the input field. These suggestions should be selectable, and when a user clicks on a suggestion, it should set the text of the input field to the selected suggestion.
Code:
I have implemented the search bar using React and have included the relevant code below:

const SearchBar = () => {
  const [searchQuery, setSearchQuery] = useState("");
  const [showSuggestion, setShowSuggestion] = useState(false);
  const [searchSuggetions, setsearchSuggetions] = useState([]);
  useEffect(() => {
    console.log("api called");
    const timer = setTimeout(() => searchSuggestions(), 200);
    return () => {
      clearTimeout(timer);
    };
  }, [searchQuery]);
  const searchSuggestions = async () => {
    const response = await fetch(
      `http://suggestqueries.google.com/complete/search?client=firefox&ds=yt&q=${searchQuery}`
    );
    const json = await response.json();
    setsearchSuggetions(json[1]);
  };
  // Function to handle suggestion item click
  const handleSuggestionClick = (result) => {
    setSearchQuery(result);
    setShowSuggestion(false); // Close suggestions after selection
  };
  const handleSearch = () => {
    console.log("called handle search");
  };
  return (
    <>
      <div className="m-2 border-2 rounded-full border-violet-500 w-60 h-8 text-violet-500 items-center inline-flex static z-10">
        <input
          value={searchQuery}
          onChange={(e) => setSearchQuery(e.target.value.toLocaleLowerCase())}
          onFocus={() => {
            setShowSuggestion(true);
          }}
          onBlur={() => {
            setShowSuggestion(false);
          }}
          type="text"
          placeholder="Find news"
          className="ml-3  focus:outline-none focus:ring-violet-300 bg-gray-900  "
        />
        <button className="hover:text-violet-700" onClick={handleSearch}>
          <svg
            xmlns="http://www.w3.org/2000/svg"
            fill="none"
            viewBox="0 0 24 24"
            strokeWidth="1.5"
            stroke="currentColor"
            className="w-6 h-6">          >
            <path
              strokeLinecap="round"
              strokeLinejoin="round"
              d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z"
            />
          </svg>
        </button>
        {showSuggestion && (
          <div className="mt-72 w-52 absolute rounded-xl bg-slate-50 z-10">
            {searchSuggetions.map((result, index) => (
              <div key={index}>
                <ul>
                  <li className="bg-slate-50 border hover:bg-slate-200 rounded-xl inline-flex cursor-pointer z-20"
                    onClick={() => {
                      console.log(result);
                      handleSuggestionClick(result);
                    }}
                  >
                    <svg xmlns="http://www.w3.org/2000/svg"
                      fill="none"
                      viewBox="0 0 24 24"
                      strokeWidth="1.5"
                      stroke="currentColor"
                      className="w-5 h-5"
                    >
                      <path
                        strokeLinecap="round"
                        strokeLinejoin="round"
                        d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z"
                      />
                    </svg>
                    <span className="w-48">{result}</span>
                  </li>
                </ul>
              </div>
            ))}
          </div>
        )}
      </div>
    </>
  );
};

2

Answers


  1. Chosen as BEST ANSWER

    In my case, the problem is occurred due to onBlur event. which is destroying the element from dom due to the selected suggestion not working after clicking on the item removed onBlur event will resolve the issue.

    import React, { useState, useEffect } from "react";
    
    const SearchBar = () => {
      const [searchQuery, setSearchQuery] = useState("");
      const [showSuggestion, setShowSuggestion] = useState(false);
      const [searchSuggestions, setSearchSuggestions] = useState([]);
    
      useEffect(() => {
        const timer = setTimeout(() => getSuggestions(), 200);
        return () => {
          clearTimeout(timer);
        };
      }, [searchQuery]);
    
      const getSuggestions = async () => {
        try {
          const response = await fetch(
            `http://suggestqueries.google.com/complete/search?client=firefox&ds=yt&q=${searchQuery}`
          );
          const json = await response.json();
          setSearchSuggestions(json[1]);
        } catch (error) {
          console.error('Error fetching suggestions:', error);
        }
      };
    
      const handleSuggestionClick = (result) => {
        console.log(result);
        setSearchQuery(result);
        setShowSuggestion(false);
      };
    
      const handleSearch = () => {
        console.log("called handle search");
        // Perform the actual search here
      };
    
      return (
        <div className="m-2 border-2 rounded-full border-violet-500 w-60 h-8 text-violet-500 items-center inline-flex relative">
          <input
            value={searchQuery}
            onChange={(e) => setSearchQuery(e.target.value)}
            onFocus={() => {
              setShowSuggestion(true);
            }}
            type="text"
            placeholder="Find news"
            className="ml-3 focus:outline-none focus:ring-violet-300 bg-gray-900"
          />
          <button className="hover:text-violet-700" onClick={handleSearch}>
            <svg
              xmlns="http://www.w3.org/2000/svg"
              fill="none"
              viewBox="0 0 24 24"
              strokeWidth="1.5"
              stroke="currentColor"
              className="w-6 h-6"
            >
              <path
                strokeLinecap="round"
                strokeLinejoin="round"
                d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z"
              />
            </svg>
          </button>
          {showSuggestion && (
            <div className="mt-1 w-60 absolute rounded-xl bg-slate-50 z-10">
              {searchSuggestions.map((result, index) => (
                <div
                  key={index}
                  className="bg-slate-50 border hover:bg-slate-200 rounded-xl flex items-center cursor-pointer z-20"
                  onClick={() => handleSuggestionClick(result)}
                >
                  <svg
                    xmlns="http://www.w3.org/2000/svg"
                    fill="none"
                    viewBox="0 0 24 24"
                    strokeWidth="1.5"
                    stroke="currentColor"
                    width="20"
                    height="20"
                    className="mr-2"
                  >
                    <path
                      strokeLinecap="round"
                      strokeLinejoin="round"
                      d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z"
                    />
                  </svg>
                  <span className="flex items-center">{result}</span>
                </div>
              ))}
            </div>
          )}
        </div>
      );
    };
    
    export default SearchBar;```
    

  2. import React, { useState, useEffect } from 'react';
    
    const SearchBar = () => {
      const [searchQuery, setSearchQuery] = useState('');
      const [showSuggestions, setShowSuggestions] = useState(false);
      const [searchSuggestions, setSearchSuggestions] = useState([]);
      
      // Function to fetch search suggestions from the API`enter code here`
      const fetchSuggestions = async () => {
        try {
          const response = await fetch(
            `http://suggestqueries.google.com/complete/search?client=firefox&ds=yt&q=${searchQuery}`
          );
          const data = await response.json();
          setSearchSuggestions(data[1]);
        } catch (error) {
          console.error('Error fetching suggestions:', error);
        }
      };
    
      useEffect(() => {
        if (searchQuery) {
          // Delay API call for a better user experience (debouncing)
          const timer = setTimeout(() => fetchSuggestions(), 300);
          return () => clearTimeout(timer);
        }
      }, [searchQuery]);
    
      // Handle input change
      const handleInputChange = (event) => {
        const inputText = event.target.value;
        setSearchQuery(inputText);
      };
    
      // Handle suggestion item click
      const handleSuggestionClick = (suggestion) => {
        setSearchQuery(suggestion);
        setShowSuggestions(false);
      };
    
      // Handle form submission (you can add your search logic here)
      const handleSearch = (event) => {
        event.preventDefault();
        console.log('Performing search with query:', searchQuery);
        // Add your search logic here (e.g., send a request to your search API)
      };
    
      return (
        <form onSubmit={handleSearch}>
          <div className="relative">
            <input
              type="text"
              value={searchQuery}
              onChange={handleInputChange}
              onFocus={() => setShowSuggestions(true)}
              onBlur={() => setShowSuggestions(false)}
              placeholder="Find news"
              className="w-60 h-8 p-2 border-2 rounded-full border-violet-500 text-violet-500 focus:outline-none focus:ring-violet-300 bg-gray-900"
            />
            <button type="submit" className="absolute right-2 top-2 hover:text-violet-700">
              <svg
                xmlns="http://www.w3.org/2000/svg"
                fill="none"
                viewBox="0 0 24 24"
                strokeWidth="1.5"
                stroke="currentColor"
                className="w-6 h-6"
              >
                {/* Your search icon SVG */}
              </svg>
            </button>
            {showSuggestions && (
              <div className="absolute top-10 left-0 z-10 bg-slate-50 border rounded-xl w-60">
                {searchSuggestions.map((result, index) => (
                  <div
                    key={index}
                    className="p-2 cursor-pointer hover:bg-slate-200"
                    onClick={() => handleSuggestionClick(result)}
                  >
                    {result}
                  </div>
                ))}
              </div>
            )}
          </div>
        </form>
      );
    };
    
    export default SearchBar;
    
    /*
        I've added an onSubmit handler to the form to capture the search query when the user submits the form. You can implement the actual search logic in this handler.
    
    I've updated the fetchSuggestions function to handle potential errors during the API call and added debouncing to the API requests for a smoother user experience.
    
    I've adjusted the positioning and styling of the search bar and suggestion dropdown to better fit the UI.
    
    The search icon in the button is a placeholder; you can replace it with your own SVG or icon.
    
    The handleInputChange function now updates the search query when the input changes.  */
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search