@react-google-maps/api无法同时渲染两个标记问题求助
解决@react-google-maps/api多标记渲染时source状态异常清空问题
问题根源
- 错误的空值判断逻辑:代码中多处使用
source.length != []、destination.length != []判断状态是否存在,但source和destination是包含lat/lng/label的对象,并非数组,不存在length属性。这种判断会导致逻辑混乱:当source存在时,source.length为undefined,与[]比较结果为true;但如果source被设为空对象或undefined,该判断依然返回true,进而尝试渲染标记时读取source.lat等属性,导致标记不显示,看起来像是source被清空。 - useEffect逻辑冗余:两个独立的
useEffect分别监听source和destination,重复调用directionRoute,且未正确处理两者同时存在的条件。
修复方案
1. 修正空值判断
将所有基于length的错误判断替换为针对对象属性的存在性检查:
原错误判断:
if (source.length != [] && destination.length != [])
替换为:
if (source && destination && source.lat && source.lng && destination.lat && destination.lng)
渲染标记时的判断同步修改:
{source && source.lat && source.lng ? ( <MarkerF ... /> ) : null}
2. 合并useEffect逻辑
将两个监听source和destination的useEffect合并为一个,同时监听两者变化,避免重复触发逻辑:
useEffect(() => { // 处理地图中心定位 if (map) { if (source?.lat && source?.lng) { map.panTo({ lat: source.lat, lng: source.lng }); setCenter({ lat: source.lat, lng: source.lng }); } if (destination?.lat && destination?.lng) { setCenter({ lat: destination.lat, lng: destination.lng }); } } // 调用路线规划 if (source?.lat && source?.lng && destination?.lat && destination?.lng) { directionRoute(); } }, [source, destination, map]);
3. 检查Context实现
确认SourceContext和DestinationContext的实现,确保setDestination方法不会意外修改source状态,比如是否在组件中误调用了setSource清空值。
修复后的完整代码
"use client"; import React, { useContext, useEffect, useState } from "react"; import { DirectionsRenderer, GoogleMap, MarkerF, OverlayView, OverlayViewF, } from "@react-google-maps/api"; import { SourceContext } from "../../context/SourceContext"; import { DestinationContext } from "../../context/DestinationContext"; function Map() { const containerStyle = { width: "100%", height: window.innerWidth * 0.8, }; const { source, setSource } = useContext(SourceContext); const { destination, setDestination } = useContext(DestinationContext); const [center, setCenter] = useState({ lat: -3.745, lng: -38.523, }); const [map, setMap] = React.useState(null); const [directionRoutePoints, setDirectionRoutePoints] = useState([]); useEffect(() => { if (map) { // 优先定位到source,若destination存在则更新中心 if (source?.lat && source?.lng) { map.panTo({ lat: source.lat, lng: source.lng }); setCenter({ lat: source.lat, lng: source.lng }); } if (destination?.lat && destination?.lng) { setCenter({ lat: destination.lat, lng: destination.lng }); } } // 当两者都存在时调用路线规划 if (source?.lat && source?.lng && destination?.lat && destination?.lng) { directionRoute(); } }, [source, destination, map]); const directionRoute = () => { const DirectionsService = new google.maps.DirectionsService(); DirectionsService.route( { origin: { lat: source.lat, lng: source.lng }, destination: { lat: destination.lat, lng: destination.lng }, travelMode: google.maps.TravelMode.DRIVING, }, (result, status) => { if (status === google.maps.DirectionsStatus.OK) { setDirectionRoutePoints(result); } else { console.error("路线规划失败:", status); } } ); }; return ( <GoogleMap mapContainerStyle={containerStyle} center={center} zoom={11} onLoad={(map) => setMap(map)} options={{ mapId: "4113717585f11867" }} > {/* 渲染起点标记 */} {source?.lat && source?.lng && ( <MarkerF position={{ lat: source.lat, lng: source.lng }} icon={{ url: "/source.png", scaledSize: { width: 20, height: 20, }, }} > <OverlayViewF position={{ lat: source.lat, lng: source.lng }} mapPaneName={OverlayView.OVERLAY_MOUSE_TARGET} > <div className="p-2 bg-white font-bold inline-block"> <p className="text-black text-[18px]">{source.label}</p> </div> </OverlayViewF> </MarkerF> )} {/* 渲染终点标记 */} {destination?.lat && destination?.lng && ( <MarkerF position={{ lat: destination.lat, lng: destination.lng }} icon={{ url: "/dest.png", scaledSize: { width: 20, height: 20, }, }} > <OverlayViewF position={{ lat: destination.lat, lng: destination.lng }} mapPaneName={OverlayView.OVERLAY_MOUSE_TARGET} > <div className="p-2 bg-white font-bold inline-block"> <p className="text-black text-[18px]">{destination.label}</p> </div> </OverlayViewF> </MarkerF> )} {/* <DirectionsRenderer directions={directionRoutePoints} options={{ polylineOptions: { strokeColor: "#000", strokeWeight: 5, }, suppressMarkers: true, }} /> */} </GoogleMap> ); } export default Map;
内容的提问来源于stack exchange,提问作者Ishfat Abrar Islam
相关产品推荐
相关产品推荐

