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

React集成Google Maps API时出现'Uncaught (in promise) TypeError'错误求助

React中Google Maps自动补全组件报错分析与解决

问题现象

使用Google Maps JavaScript API实现地点自动补全组件时,持续触发以下错误:

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'zt')

组件实现代码

import React, { useRef, useEffect, useState } from "react";

function GoogleMapsAutocomplete({ onPlaceSelect }) {
  const autocompleteInput = useRef(null);
  const [autocomplete, setAutocomplete] = useState(null);

  useEffect(() => {
    const loadGoogleMapsScript = () => {
      // 检查Google Maps脚本是否已加载
      if (!window.google) {
        const script = document.createElement("script");
        script.src = `https://maps.googleapis.com/maps/api/js?key=MyAPIKey&libraries=places`;
        script.async = true;
        script.defer = true;

        // 通过回调确保初始化完成
        script.onload = () => {
          initAutocomplete();
        };

        document.head.appendChild(script);
      } else {
        initAutocomplete();
      }
    };

    const initAutocomplete = () => {
      const auto = new window.google.maps.places.Autocomplete(
        autocompleteInput.current
      );
      auto.addListener("place_changed", handlePlaceSelect);
      setAutocomplete(auto); // 初始化完成后保存autocomplete对象
    };

    const handlePlaceSelect = () => {
      if (autocomplete) {
        // 检查autocomplete是否已定义
        const selectedPlace = autocomplete.getPlace();
        if (selectedPlace) {
          onPlaceSelect(selectedPlace);
        }
      }
    };

    loadGoogleMapsScript();
  }, [onPlaceSelect]);

  return (
    <div>
      <input
        ref={autocompleteInput}
        type="text"
        placeholder="Enter a location"
      />
    </div>
  );
}

export default GoogleMapsAutocomplete;

错误原因分析

  1. 状态异步更新导致的实例获取延迟:handlePlaceSelect依赖组件状态autocomplete,但setAutocomplete是异步操作,当place_changed事件触发时,状态可能还未完成更新,此时autocomplete为null,调用其方法会引发API内部错误。
  2. DOM元素未完全挂载:组件挂载时autocompleteInput.current可能还未插入DOM树,直接传入Google Maps API会导致初始化异常,触发内部属性未定义的报错。
  3. 重复初始化风险:若组件多次渲染,可能重复创建Autocomplete实例,引发API内部状态冲突。

解决方法

方案1:直接使用局部实例处理事件

避免依赖组件状态,在初始化时直接用创建的auto实例绑定事件:

const initAutocomplete = () => {
  if (!autocompleteInput.current) return; // 确保DOM元素存在
  const auto = new window.google.maps.places.Autocomplete(
    autocompleteInput.current
  );
  // 直接使用局部实例处理事件,跳过组件状态依赖
  auto.addListener("place_changed", () => {
    const selectedPlace = auto.getPlace();
    if (selectedPlace) {
      onPlaceSelect(selectedPlace);
    }
  });
  setAutocomplete(auto);
};

方案2:确保DOM完全挂载后初始化

使用useLayoutEffect替代useEffect,确保DOM更新完成后再执行API初始化:

useLayoutEffect(() => {
  const loadGoogleMapsScript = () => {
    // 原有脚本加载逻辑不变
    if (!window.google) {
      const script = document.createElement("script");
      script.src = `https://maps.googleapis.com/maps/api/js?key=MyAPIKey&libraries=places`;
      script.async = true;
      script.defer = true;
      script.onload = () => initAutocomplete();
      document.head.appendChild(script);
    } else {
      initAutocomplete();
    }
  };

  const initAutocomplete = () => {
    if (!autocompleteInput.current) return;
    const auto = new window.google.maps.places.Autocomplete(
      autocompleteInput.current
    );
    auto.addListener("place_changed", () => {
      const selectedPlace = auto.getPlace();
      if (selectedPlace) {
        onPlaceSelect(selectedPlace);
      }
    });
    setAutocomplete(auto);
  };

  loadGoogleMapsScript();
}, [onPlaceSelect]);

方案3:添加初始化标记防止重复创建实例

使用useRef标记是否已完成初始化,避免重复创建Autocomplete实例:

const autocompleteInput = useRef(null);
const [autocomplete, setAutocomplete] = useState(null);
const isInitialized = useRef(false); // 初始化状态标记

useEffect(() => {
  if (isInitialized.current) return;

  const loadGoogleMapsScript = () => {
    if (!window.google) {
      const script = document.createElement("script");
      script.src = `https://maps.googleapis.com/maps/api/js?key=MyAPIKey&libraries=places`;
      script.async = true;
      script.defer = true;
      script.onload = () => initAutocomplete();
      document.head.appendChild(script);
    } else {
      initAutocomplete();
    }
  };

  const initAutocomplete = () => {
    if (!autocompleteInput.current) return;
    const auto = new window.google.maps.places.Autocomplete(
      autocompleteInput.current
    );
    auto.addListener("place_changed", () => {
      const selectedPlace = auto.getPlace();
      if (selectedPlace) {
        onPlaceSelect(selectedPlace);
      }
    });
    setAutocomplete(auto);
    isInitialized.current = true; // 标记已完成初始化
  };

  loadGoogleMapsScript();

  // 组件卸载时清理监听
  return () => {
    if (autocomplete) {
      window.google.maps.event.clearInstanceListeners(autocomplete);
    }
    isInitialized.current = false;
  };
}, [onPlaceSelect]);

额外注意事项

  • 确认你的API密钥已启用Places API权限,且未超出调用配额或被限制访问。
  • 若为SPA应用,建议将Google Maps脚本加载放在全局入口文件中,避免组件重复处理脚本加载逻辑。

内容的提问来源于stack exchange,提问作者Leonardo Picchi Lpdancona

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 02:36:14