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

设置新路线时旧路线未清除的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 23:40:42