You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React字典应用:搜索词清空/点击外部时自动建议下拉框未消失

解决方案

针对你遇到的两个问题,以下是具体修改方案:

问题1:清空搜索栏时下拉框仍显示

当搜索框内容被清空时,需要主动关闭下拉框并清空建议列表。修改handleInputChange函数,判断输入值为空时执行对应操作:

const handleInputChange = async (e) => {
  const inputVal = e.target.value;
  setValue(inputVal);
  
  // 输入为空时,关闭下拉框并清空建议
  if (!inputVal) {
    setSearchSuggestions([]);
    setIsDropdownOpen(false);
    return;
  }
  
  const suggestions = await getWordSuggestions(inputVal);
  setSearchSuggestions(suggestions);
  setIsDropdownOpen(true);
};

同时优化下拉框的显示条件,确保只有存在建议时才显示:

{isDropdownOpen && searchSuggestions.length > 0 && (
  <div className="word-suggestion-dropdown should-be-in-a-container absolute top-full bg-gray-50 w-full z-10">
    {searchSuggestions.map((word) => {
      return (
        <WordItem
          key={word}
          word={word}
          handleClick={handleSubmit}
        />
      );
    })}
  </div>
)}

问题2:点击浏览器任意位置时下拉框不消失

添加外部点击监听逻辑,使用useRef获取搜索容器元素,结合useEffect监听文档点击事件:

  1. 导入所需Hook:
import { useContext, useState, useRef, useEffect } from "react";
  1. 创建容器Ref:
const searchContainerRef = useRef(null);
  1. 为form元素绑定Ref:
<form
  ref={searchContainerRef}
  className="relative flex border-2 border-gray-200 rounded"
  onSubmit={handleShowResult}
>
  1. 添加外部点击监听的Effect:
useEffect(() => {
  const handleClickOutside = (event) => {
    // 判断点击位置是否在搜索容器之外
    if (searchContainerRef.current && !searchContainerRef.current.contains(event.target)) {
      setIsDropdownOpen(false);
    }
  };

  document.addEventListener("mousedown", handleClickOutside);
  // 组件卸载时移除监听
  return () => {
    document.removeEventListener("mousedown", handleClickOutside);
  };
}, []);

修改后的完整Header.js代码

import { useContext, useState, useRef, useEffect } from "react";
import { InputContext } from "../App";
import { getWordSuggestions } from "../api/getWordSuggestions";
import WordItem from "./WordItem";

const Header = () => {
  const [value, setValue] = useState("");
  const [isDropdownOpen, setIsDropdownOpen] = useState(false);
  const [searchSuggestions, setSearchSuggestions] = useState([]);
  const { inputValue, setInputValue } = useContext(InputContext);
  const searchContainerRef = useRef(null);

  const handleSubmit = (word) => {
    setInputValue(word);
    setValue("");
    setSearchSuggestions([]);
    setIsDropdownOpen(false);
  };

  // On change of search field
  const handleInputChange = async (e) => {
    const inputVal = e.target.value;
    setValue(inputVal);
    
    if (!inputVal) {
      setSearchSuggestions([]);
      setIsDropdownOpen(false);
      return;
    }
    
    const suggestions = await getWordSuggestions(inputVal);
    setSearchSuggestions(suggestions);
    setIsDropdownOpen(true);
  };

  // To submit the form
  const handleShowResult = (e) => {
    e.preventDefault();
    handleSubmit(value);
  };

  useEffect(() => {
    const handleClickOutside = (event) => {
      if (searchContainerRef.current && !searchContainerRef.current.contains(event.target)) {
        setIsDropdownOpen(false);
      }
    };

    document.addEventListener("mousedown", handleClickOutside);
    return () => {
      document.removeEventListener("mousedown", handleClickOutside);
    };
  }, []);

  return (
    <div className="bg-gray-700">
      <div className="container mx auto py-8">
        <h1 className="text-3xl font-bold text-center text-white">
          My Free Dictionary
        </h1>
        <p className="text-center mt-1 mb-10 text-white text-lg">
          Find Definitions for word
        </p>

        <div className="flex items-center justify-center mt-5">
          <form
            ref={searchContainerRef}
            className="relative flex border-2 border-gray-200 rounded"
            onSubmit={handleShowResult}
          >
            <input
              className="px-4 py-2 md:w-80"
              type="text"
              placeholder="Search.."
              onChange={handleInputChange}
              value={value}
              onFocus={() => {
                if (value) setIsDropdownOpen(true);
              }}
            />
            <button className="bg-blue-400 border-l px-4 py-2 text-white">
              Search
            </button>
            {isDropdownOpen && searchSuggestions.length > 0 && (
              <div className="word-suggestion-dropdown should-be-in-a-container absolute top-full bg-gray-50 w-full z-10">
                {searchSuggestions.map((word) => {
                  return (
                    <WordItem
                      key={word}
                      word={word}
                      handleClick={handleSubmit}
                    />
                  );
                })}
              </div>
            )}
          </form>
        </div>
        {inputValue && (
          <h3 className="text-gray-50 text-center mt-4">
            Results for:{" "}
            <span className="text-white font-bold">{inputValue}</span>
          </h3>
        )}
      </div>
    </div>
  );
};

export default Header;

内容的提问来源于stack exchange,提问作者Shlomy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 19:35:36