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

React中Google未定义问题:如何检测Google Maps脚本是否加载完成

我之前也碰到过一模一样的问题——网络不给力的时候,Google Maps脚本加载慢半拍,直接导致渲染时google对象未定义的报错。不用react-async-script-loader的话,有几个不用大改代码的方案可以试试:

方案一:监听脚本加载事件,用状态控制渲染时机

这是最直接的方法,给你动态创建的脚本添加onload和onerror事件,只有当脚本加载完成后才渲染包含地图的组件。修改你的代码如下:

constructor(props) {
  super(props);
  this.state = {
    isMapLoaded: false,
    mapLoadFailed: false
  };
}

componentWillMount() {
  const API_KEY = process.env.GOOGLEMAP_API_KEY;
  const script = document.createElement('script');
  script.src = `https://maps.googleapis.com/maps/api/js?key=${API_KEY}`;
  script.async = true;
  script.defer = true;

  // 脚本加载成功,标记状态
  script.onload = () => {
    this.setState({ isMapLoaded: true });
  };

  // 脚本加载失败(比如API密钥错误、网络完全中断)
  script.onerror = () => {
    this.setState({ mapLoadFailed: true });
  };

  document.head.append(script);
}

renderApp() {
  return (
    <div>
      <Header />
      <Main />
    </div>
  );
}

render() {
  // 加载失败的提示
  if (this.state.mapLoadFailed) {
    return <div>地图加载失败,请检查网络或稍后重试</div>;
  }

  // 未加载完成时显示加载状态
  if (!this.state.isMapLoaded) {
    return <div>正在加载地图...</div>; // 可以换成你的加载动画组件
  }

  return <div>{this.renderApp()}</div>;
}

这个方案的核心是通过脚本的onload事件确认Google Maps API已完全加载,再通过组件状态控制渲染,从根源上避免google is undefined的问题。

方案二:轮询检查google对象,兼容复杂加载场景

如果你的脚本可能在多个地方被加载,或者想兼容脚本已提前加载的情况,可以用轮询的方式定期检查google对象是否存在:

constructor(props) {
  super(props);
  this.state = {
    isMapLoaded: false,
    mapLoadTimeout: false
  };
  this.checkInterval = null;
}

componentDidMount() {
  // 先检查是否已经加载完成
  if (typeof google !== 'undefined' && google.maps) {
    this.setState({ isMapLoaded: true });
    return;
  }

  // 启动轮询,每隔300ms检查一次,超时时间设为10秒
  const timeoutLimit = 10000;
  const startTime = Date.now();

  this.checkInterval = setInterval(() => {
    if (typeof google !== 'undefined' && google.maps) {
      clearInterval(this.checkInterval);
      this.setState({ isMapLoaded: true });
    } else if (Date.now() - startTime > timeoutLimit) {
      clearInterval(this.checkInterval);
      this.setState({ mapLoadTimeout: true });
    }
  }, 300);

  // 确保脚本被加载(避免重复加载)
  const API_KEY = process.env.GOOGLEMAP_API_KEY;
  const existingScript = document.querySelector(`script[src="https://maps.googleapis.com/maps/api/js?key=${API_KEY}"]`);
  if (!existingScript) {
    const script = document.createElement('script');
    script.src = `https://maps.googleapis.com/maps/api/js?key=${API_KEY}`;
    script.async = true;
    script.defer = true;
    document.head.append(script);
  }
}

componentWillUnmount() {
  // 清理定时器,防止内存泄漏
  if (this.checkInterval) {
    clearInterval(this.checkInterval);
  }
}

render() {
  if (this.state.mapLoadTimeout) {
    return <div>地图加载超时,请检查网络连接</div>;
  }

  if (!this.state.isMapLoaded) {
    return <div>正在加载地图...</div>;
  }

  return <div>{this.renderApp()}</div>;
}

这个方案适合脚本加载时机不确定的场景,轮询能确保等到google对象可用后再渲染组件。记得在组件卸载时清理定时器,避免内存泄漏。

方案三:通过HTML脚本的callback参数触发渲染

把脚本加载放到index.html中,利用Google Maps API的callback参数指定一个全局函数,当脚本加载完成时触发这个函数,通知React应用开始渲染:

首先在index.html中添加脚本:

<script src="https://maps.googleapis.com/maps/api/js?key=%REACT_APP_GOOGLEMAP_API_KEY%&callback=onMapLoaded" async defer></script>

然后修改你的App组件:

constructor(props) {
  super(props);
  this.state = {
    isMapLoaded: false
  };

  // 定义全局回调函数
  window.onMapLoaded = () => {
    this.setState({ isMapLoaded: true });
  };
}

render() {
  if (!this.state.isMapLoaded) {
    return <div>加载中...</div>;
  }

  return <div>{this.renderApp()}</div>;
}

这种方法把脚本加载交给HTML处理,通过官方的回调机制确保加载完成后再渲染,缺点是要注意全局函数的命名冲突问题。

个人最推荐方案一,因为它和你现有的代码结构最契合,改动最小,逻辑也最清晰,能完美解决网络慢导致的加载时序问题。

内容的提问来源于stack exchange,提问作者bigmugcup

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:51:03