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

Storybook中Google Maps初始化停滞问题求助

在Storybook中初始化Google Maps停滞的排查方案

问题背景

代码在常规预览环境中可正常运行,但在Storybook中调用new google.maps.Map(document.getElementById('map-container'))初始化地图时,地图对象始终处于未完成状态:__gm.isInitialized为false,__gm.o是一个pending状态的Promise,仅能看到占位图,动态地图无法加载。

排查与解决方法

1. 修正初始化时机,依赖组件生命周期而非定时器

Storybook的渲染时序与普通环境存在差异,setTimeout的延迟逻辑不可靠,改用React的useEffect确保在组件挂载后、容器元素存在的前提下执行初始化:

export const Map: ComponentStory<typeof MyMaps> = () => {
  useEffect(() => {
    // 先校验Google Maps API是否加载完成
    if (!window.google?.maps) return;
    
    const container = document.getElementById('map-container');
    if (!container) return;

    const map = new google.maps.Map(container, {
      center: { lat: 40.747445, lng: -74.000704 }, 
      zoom: 12
    });

    // 监听地图idle事件,确认初始化完成
    google.maps.event.addListenerOnce(map, 'idle', () => {
      console.log('地图初始化完成');
    });
  }, []);

  return (
    <div style={{ height: '100%', width: '100%' }}>
      <div id="map-container" style={{ height: '200px', width: '200px', border: '1px solid' }}></div>
    </div>
  );
};

2. 解除Storybook iframe的环境限制

Storybook预览在iframe中运行,可能存在权限或资源加载限制:

  • 在.storybook/preview.js中配置iframe权限:
    export const parameters = {
      iframe: {
        allow: "geolocation *; fullscreen *; autoplay *; encrypted-media *"
      },
    };
    
  • 在.storybook/main.js中配置内容安全策略(CSP),允许Google Maps相关资源加载:
    module.exports = {
      async headers() {
        return [
          {
            source: '/preview.html',
            headers: [
              {
                key: 'Content-Security-Policy',
                value: "script-src 'self' 'unsafe-inline' 'unsafe-eval' https://maps.googleapis.com https://maps.gstatic.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: https://*.google.com https://*.gstatic.com;",
              },
            ],
          },
        ];
      },
    };
    

3. 追踪pending状态的Promise

利用Chrome DevTools定位Promise停滞原因:

  • 在Sources面板的XHR/fetch断点中添加maps.googleapis.com,检查API请求是否成功返回;
  • 在控制台执行以下代码,监听Promise的状态变化:
    const mapPromise = document.getElementById('map-container')?.__gm?.o;
    if (mapPromise) {
      mapPromise.then(() => console.log('Promise 已 resolve')).catch(err => console.error('Promise 已 reject', err));
    }
    
  • 使用Performance面板录制渲染过程,排查是否有阻塞任务导致初始化停滞。

4. 校验容器元素的可见性与尺寸

Storybook预览容器可能在初始化时尺寸为0或不可见,导致地图无法渲染:

useEffect(() => {
  const container = document.getElementById('map-container');
  if (!container || !window.google?.maps) return;

  const rect = container.getBoundingClientRect();
  if (rect.width === 0 || rect.height === 0) {
    console.warn('容器尺寸为0,无法初始化地图');
    return;
  }

  const map = new google.maps.Map(container, {
    center: { lat: 40.747445, lng: -74.000704 }, 
    zoom: 12
  });
}, []);

5. 构建最小化复现案例

创建仅包含地图初始化的独立Story,排除其他组件逻辑的干扰;同时在普通React项目中复现相同代码,对比Storybook与常规环境的差异,定位环境专属问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 23:35:29