设置新路线时旧路线未清除的Google Maps API问题
问题:Google Maps Directions API多次绘制路线叠加,旧路线无法清除
使用Google Maps Directions API在地图上绘制路线时,首次调用DirectionsRenderer.setDirections(response)功能正常,但第二次调用时旧路线会保留并与新路线叠加。尝试过directionsRenderer.setDirections(null)或directionsRenderer.setMap(null)均无效,原本以为.setDirections()会覆盖旧路线,现在发现地图上的路线和DirectionsRenderer存储的路线似乎解耦了。
相关代码
路线计算函数
export async function testRouteCalculation( directionsService: google.maps.DirectionsService, directionsRenderer: google.maps.DirectionsRenderer, withWaypoints: boolean, numWaypointsToInclude: number ) { let request: google.maps.DirectionsRequest = { origin: testOrigin, destination: testDestination, travelMode: google.maps.TravelMode["DRIVING"], unitSystem: google.maps.UnitSystem.METRIC, provideRouteAlternatives: false, // region is specified for region biasing region: "za", waypoints: [], }; if (withWaypoints) { for (let i = 0; i < numWaypointsToInclude; i++) { request!.waypoints!.push(testWaypoints[i]); } } try { const response = await directionsService.route(request); return response; } catch (err) { throw err; } }
React地图组件
const Map = () => { const ref = React.useRef<HTMLDivElement>(null); const [map, setMap] = React.useState<google.maps.Map>(); const [directionsRenderer, setDirectionsRenderer] = React.useState<google.maps.DirectionsRenderer>(); const [directionsService, setDirectionsService] = React.useState<google.maps.DirectionsService>(); React.useEffect(() => { let newMap = null; if (ref.current && !map) { newMap = new window.google.maps.Map(ref.current, { center: capeTownCoordinates, zoom: 13, streetViewControl: false, mapTypeControl: false, }); setMap(newMap); } const newDirectionsRenderer = new google.maps.DirectionsRenderer(); newDirectionsRenderer.setMap(newMap); setDirectionsRenderer(newDirectionsRenderer); setDirectionsService(new google.maps.DirectionsService()); }, [ref, map]); if (map && directionsRenderer && !directionsRenderer.getMap()) { directionsRenderer.setMap(map); } const handleClick = async () => { if (directionsRenderer && directionsService) { try { const response = await testRouteCalculation( directionsService, directionsRenderer, true, 2 ); directionsRenderer.setDirections(response); } catch (err) { console.log(err); } } else { console.log("no directionsRenderer or directionsService object"); } }; return ( <> <div id="map" style={{ height: "300px", width: "400px" }} ref={ref}></div> <button onClick={handleClick} className={styles["floating-button"]}> Get route </button> </> ); };
问题根源
你的问题出在useEffect的依赖配置和实例创建逻辑:
- useEffect的依赖包含
map,每次map状态更新时,都会创建一个新的DirectionsRenderer实例并绑定到地图上 - 旧的
DirectionsRenderer实例没有被从地图上移除,仍然保留着之前绘制的路线 - 后续调用
setDirections时,仅更新了最新的DirectionsRenderer实例,但旧实例的路线还在地图上,最终导致路线叠加
解决方案
方案1:使用Ref存储单例实例(推荐)
调整逻辑,仅在地图初始化时创建一次DirectionsRenderer和DirectionsService实例,用Ref存储避免重复创建:
const Map = () => { const ref = React.useRef<HTMLDivElement>(null); const [map, setMap] = React.useState<google.maps.Map>(); // 用Ref存储实例,避免状态更新导致重建 const directionsRendererRef = React.useRef<google.maps.DirectionsRenderer>(); const directionsServiceRef = React.useRef<google.maps.DirectionsService>(); React.useEffect(() => { if (ref.current && !map) { const newMap = new window.google.maps.Map(ref.current, { center: capeTownCoordinates, zoom: 13, streetViewControl: false, mapTypeControl: false, }); setMap(newMap); // 仅初始化一次服务和渲染器 const renderer = new google.maps.DirectionsRenderer(); renderer.setMap(newMap); directionsRendererRef.current = renderer; directionsServiceRef.current = new google.maps.DirectionsService(); } }, [ref, map]); const handleClick = async () => { const renderer = directionsRendererRef.current; const service = directionsServiceRef.current; if (renderer && service) { try { const response = await testRouteCalculation( service, renderer, true, 2 ); // 同一实例调用setDirections会直接覆盖旧路线 renderer.setDirections(response); } catch (err) { console.log(err); } } else { console.log("未初始化directionsRenderer或directionsService"); } }; return ( <> <div id="map" style={{ height: "300px", width: "400px" }} ref={ref}></div> <button onClick={handleClick} className={styles["floating-button"]}> 获取路线 </button> </> ); };
方案2:清理旧实例再创建新实例
如果必须在某些条件下重建实例,需要先将旧实例从地图上解绑:
const Map = () => { const ref = React.useRef<HTMLDivElement>(null); const [map, setMap] = React.useState<google.maps.Map>(); const [directionsRenderer, setDirectionsRenderer] = React.useState<google.maps.DirectionsRenderer>(); const [directionsService, setDirectionsService] = React.useState<google.maps.DirectionsService>(); React.useEffect(() => { let newMap = null; if (ref.current && !map) { newMap = new window.google.maps.Map(ref.current, { center: capeTownCoordinates, zoom: 13, streetViewControl: false, mapTypeControl: false, }); setMap(newMap); } // 清理旧的渲染器,从地图上移除 if (directionsRenderer) { directionsRenderer.setMap(null); } const newRenderer = new google.maps.DirectionsRenderer(); newRenderer.setMap(newMap); setDirectionsRenderer(newRenderer); setDirectionsService(new google.maps.DirectionsService()); }, [ref, map, directionsRenderer]); // 添加directionsRenderer到依赖 const handleClick = async () => { if (directionsRenderer && directionsService) { try { const response = await testRouteCalculation( directionsService, directionsRenderer, true, 2 ); directionsRenderer.setDirections(response); } catch (err) { console.log(err); } } else { console.log("未初始化directionsRenderer或directionsService"); } }; return ( <> <div id="map" style={{ height: "300px", width: "400px" }} ref={ref}></div> <button onClick={handleClick} className={styles["floating-button"]}> 获取路线 </button> </> ); };
补充说明
DirectionsRenderer.setDirections()本身是会覆盖当前实例的路线的,问题核心是存在多个活跃的渲染器实例绑定在地图上- 使用Ref存储Google Maps对象比State更合适,因为State更新会触发组件重渲染,而这类实例不需要参与React的状态流转
内容的提问来源于stack exchange,提问作者AlePouroullis
相关产品推荐
相关产品推荐

