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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 09:20:58