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监听文档点击事件:
- 导入所需Hook:
import { useContext, useState, useRef, useEffect } from "react";
- 创建容器Ref:
const searchContainerRef = useRef(null);
- 为form元素绑定Ref:
<form ref={searchContainerRef} className="relative flex border-2 border-gray-200 rounded" onSubmit={handleShowResult} >
- 添加外部点击监听的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
相关产品推荐
相关产品推荐

