React中Google Maps API自动补全:箭头键选择后回车无效问题
问题原因
当通过箭头键选中Autocomplete下拉项并按回车时,自定义的onKeyDown回车事件会优先触发,此时location状态还未通过place_changed事件更新(React状态更新是异步的),导致搜索使用的仍是手动输入的原始值,而非选中的地点。
解决方案
1. 保存Autocomplete实例到Ref
需要在回车事件中直接访问Autocomplete实例,因此新增ref存储该实例:
const autocompleteRef = useRef(null); // 新增用于存储Autocomplete实例的ref const initializeAutocomplete = () => { if (!autocompleteInputRef.current || !window.google) return; const autocomplete = new window.google.maps.places.Autocomplete( autocompleteInputRef.current, ); autocompleteRef.current = autocomplete; // 保存实例到ref autocomplete.addListener("place_changed", () => { const place = autocomplete.getPlace(); const address = place.formatted_address || place.name; setLocation(address); }); };
2. 修改回车事件逻辑
在输入框的onKeyDown中,先判断是否有选中的Autocomplete预测项,确保优先处理选中的地点后再执行搜索:
onKeyDown={e => { if (e.key === "Enter" && location.trim()) { e.preventDefault(); // 阻止默认回车行为,避免与Google的Autocomplete逻辑冲突 const autocomplete = autocompleteRef.current; if (autocomplete) { const selectedPlace = autocomplete.getPlace(); // 判断是否有选中的有效地点 if (selectedPlace && (selectedPlace.formatted_address || selectedPlace.name)) { const address = selectedPlace.formatted_address || selectedPlace.name; setLocation(address); // 延迟执行搜索,确保React状态更新完成 setTimeout(() => { searchLocationWithVerification(); }, 0); } else { // 无选中项,直接使用当前输入值搜索 searchLocationWithVerification(); } } else { // Autocomplete未初始化,直接执行搜索 searchLocationWithVerification(); } } }}
3. 修复代码语法错误
原代码中searchLocation函数的try块未闭合,补充完整:
const searchLocation = async () => { try { if (location !== searchedLocation) { setIsSearching(true); // ### STUFF FOR GETTING DATA ### setSearchedLocation(location); setIsSearching(false); } } catch (e) { setIsSearching(false); console.error(e); } // 补充闭合括号 };
完整核心代码片段
function App() { const [captchaVerified, setCaptchaVerified] = useState(false); const onCaptchaChange = (value) => { setCaptchaVerified(!!value); }; const autocompleteInputRef = useRef(null); const autocompleteRef = useRef(null); // 新增Autocomplete实例ref const loadGooglePlacesScript = () => { if (window.google) { initializeAutocomplete(); return; } const script = document.createElement("script"); script.src = `https://maps.googleapis.com/maps/api/js?key=${process.env.REACT_APP_GOOGLE_MAPS_API_KEY}&libraries=places`; script.onload = () => initializeAutocomplete(); document.body.appendChild(script); }; const initializeAutocomplete = () => { if (!autocompleteInputRef.current || !window.google) return; const autocomplete = new window.google.maps.places.Autocomplete( autocompleteInputRef.current, ); autocompleteRef.current = autocomplete; autocomplete.addListener("place_changed", () => { const place = autocomplete.getPlace(); const address = place.formatted_address || place.name; setLocation(address); }); }; const [isSearching, setIsSearching] = useState(false); const [location, setLocation] = useState(""); const [searchedLocation, setSearchedLocation] = useState(""); const searchLocationWithVerification = async () => { if (!captchaVerified) { alert("captcha not verified."); return; } await searchLocation(); }; const searchLocation = async () => { try { if (location !== searchedLocation) { setIsSearching(true); // ### STUFF FOR GETTING DATA ### setSearchedLocation(location); setIsSearching(false); } } catch (e) { setIsSearching(false); console.error(e); } }; useEffect(() => { loadGooglePlacesScript(); }, []); return ( <div className="App"> <div className="search-bar-launch-container"> <div className="input-container"> <input ref={autocompleteInputRef} value={location} onChange={e => setLocation(e.target.value)} onKeyDown={e => { if (e.key === "Enter" && location.trim()) { e.preventDefault(); const autocomplete = autocompleteRef.current; if (autocomplete) { const selectedPlace = autocomplete.getPlace(); if (selectedPlace && (selectedPlace.formatted_address || selectedPlace.name)) { const address = selectedPlace.formatted_address || selectedPlace.name; setLocation(address); setTimeout(() => { searchLocationWithVerification(); }, 0); } else { searchLocationWithVerification(); } } else { searchLocationWithVerification(); } } }} placeholder="Enter address or coordinates" className="input" /> </div> <div className="captcha-container"> <ReCAPTCHA sitekey={process.env.REACT_APP_GOOGLE_CAPTCHA_KEY} onChange={onCaptchaChange} /> </div> </div> </div> ) }
内容的提问来源于stack exchange,提问作者Soup
相关产品推荐
相关产品推荐

