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
相关产品推荐
相关产品推荐

