React+Firebase v9 Firestore自动补全点击写入空白问题求助
问题描述
使用ReactJS、Firestore - Firebase v9开发。
我用纯React搭建了网页自动补全搜索栏,该问题已困扰我至少一个月:能否让该自动补全输入框与Firestore联动?即用户输入例如“elepha”时,显示包含“elephant”的建议(此部分已实现),用户点击“elephant”建议项后,将该词写入Firestore。
由于网上无相关解决方案,我想知道该需求是否可行。
我的简易自动补全栏代码(animals_data为存储动物名称的文件):
我尝试添加onClick={pleaseSend}(基础addDoc函数),但点击建议项后,Firestore中仅存入空白值""。
<SearchBar data={animals_data} />
过滤代码如下:
function SearchBar({ placeholder, data }) { const [filteredData, setFilteredData] = useState([]); const [wordEntered, setWordEntered] = useState(""); const [newAnswer, setAnswer] = useState("") const [users, setUsers] = useState([]); const usersCollectionRef = collection(db, "Answers") const createUser = async () => { await addDoc(usersCollectionRef, {name: newAnswer}).then(()=>{ window.location.reload() }).catch((err)=>{ console.log(err) }) }; const handleFilter = (event) => { const searchWord = event.target.value; setWordEntered(searchWord); const newFilter = data.filter((value) => { return value.full_name.toLowerCase().includes(searchWord.toLowerCase()); }); if (searchWord === "") { setFilteredData([]); } else { setFilteredData(newFilter); } }; const clearInput = () => { setFilteredData([]); setWordEntered(""); }; return ( <div className="search"> <div className="searchInputs"> <input type="text" placeholder={placeholder} value={wordEntered} onChange={handleFilter} /> </div> {filteredData.length !== 0 && ( <div className="dataResult"> {filteredData.slice(0, 15).map((value, key) => { return ( <a className="dataItem" onClick={createUser} target="_blank"> <p>{value.full_name} </p> </a> ); })} </div> )} </div> ); } export default SearchBar;
解决方案
需求可行性
完全可行,你遇到的空白值问题是因为点击建议项时,没有将选中的动物名称传递给Firestore写入函数,导致newAnswer状态始终为空。
具体修复步骤
传递选中的名称到写入函数
在渲染建议项的map方法中,修改onClick事件,将当前项的value.full_name作为参数传入createUser:<a className="dataItem" key={key} onClick={() => createUser(value.full_name)}> <p>{value.full_name}</p> </a>(注:移除了不必要的
target="_blank",避免意外跳转;同时添加key属性符合React列表渲染规范)修改写入函数接收参数
更新createUser函数,直接使用传入的选中名称写入Firestore,无需依赖newAnswer状态:const createUser = async (selectedName) => { try { await addDoc(usersCollectionRef, { name: selectedName }); window.location.reload(); // 若无需刷新页面可删除此行 } catch (err) { console.error(err); } };清理冗余状态
删除未使用的newAnswer状态:// 移除该行 const [newAnswer, setAnswer] = useState("")
修复后完整代码
function SearchBar({ placeholder, data }) { const [filteredData, setFilteredData] = useState([]); const [wordEntered, setWordEntered] = useState(""); const [users, setUsers] = useState([]); const usersCollectionRef = collection(db, "Answers") const createUser = async (selectedName) => { try { await addDoc(usersCollectionRef, { name: selectedName }); window.location.reload(); } catch (err) { console.error(err); } }; const handleFilter = (event) => { const searchWord = event.target.value; setWordEntered(searchWord); const newFilter = data.filter((value) => { return value.full_name.toLowerCase().includes(searchWord.toLowerCase()); }); if (searchWord === "") { setFilteredData([]); } else { setFilteredData(newFilter); } }; const clearInput = () => { setFilteredData([]); setWordEntered(""); }; return ( <div className="search"> <div className="searchInputs"> <input type="text" placeholder={placeholder} value={wordEntered} onChange={handleFilter} /> </div> {filteredData.length !== 0 && ( <div className="dataResult"> {filteredData.slice(0, 15).map((value, key) => { return ( <a className="dataItem" key={key} onClick={() => createUser(value.full_name)}> <p>{value.full_name}</p> </a> ); })} </div> )} </div> ); } export default SearchBar;
额外优化建议
- 点击建议项后,可将选中名称填充到输入框:在
createUser函数中添加setWordEntered(selectedName),同时调用setFilteredData([])关闭下拉列表。 - 移除
window.location.reload(),改用状态更新实现页面数据同步,提升用户体验。
内容的提问来源于stack exchange,提问作者Simon
相关产品推荐
相关产品推荐

