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

react-leaflet中map已渲染却报null的弹窗打开异常问题

解决Leaflet地图Popup打开时map为null的报错问题

问题描述

设置了Popup的打开条件,当controlInfoWindow返回true时需要打开弹窗,但控制台显示map和marker的值均不为null的情况下,依然出现map为null的报错。

相关代码

控制弹窗显示的函数

const controlInfoWindow = () => {
const marker = markerRef?.current;

    if (map != null && marker != null) {
      if (totalDeviceBtnClick == true) {
        return true;
      } else if (props.filter) {
        return true;
      } else if (
        props.routeControl == 0 &&
        props.areaFenceControl == 0 &&
        props.showPopUpBox == false &&
        props.ambulanceTraumaMedLatLng.length == 0
      ) {
        if (
          marker !== null &&
          typeof marker == "object" &&
          Object.keys(marker).length !== 0
        ) {
        }
        return true;
      } else if (
        props.routeControl == 1 &&
        props.areaFenceControl == 0 &&
        props.showPopUpBox == true
      ) {
        // marker?.openPopup();
        return true;
      } else if (
        props.routeControl == 0 &&
        props.areaFenceControl == 1 &&
        props.showPopUpBox == true
      ) {
        // debugger;
        return true;
      } else if (
        props.routeControl == 1 &&
        props.areaFenceControl == 1 &&
        props.showPopUpBox == true
      ) {
        return true;
      }
      else {
        return false;
      }
    }

};

触发弹窗的副作用

useEffect(() => {
const marker = markerRef?.current;
if (controlInfoWindow() == true && map != null) {
if (
marker !== null &&
typeof marker == "object" &&
Object.keys(marker).length !== 0
) {
marker?.openPopup();
}
}
}, [map, markerRef.current, controlInfoWindow]);

Map状态同步逻辑

const [map, setMap] = useState();
const MyMap = ({ setMap }) => {
const map = useMap();

useEffect(() => {
setMap(map);
}, []);

return null;
};

完整地图组件

<MapContainer
  style={{ height: "100%" }}
   center={path?.length == 0 && props?.areaFenceControl == 0 ? apiData.length > 0
            ? { lat: mapData?.latitude, lng: mapData?.longitude }
             : { lat: 20.3341125, lng: 85.8012031 }
            : center
          }
    ref={mapRef}
    zoom={zoom}
    minZoom={parseInt(process.env.REACT_APP_MAP_MIN_ZOOM_LEVEL)}
    scrollWheelZoom={true}
  >
  <TileLayer url={osm.maptiler.url} attribution={osm.maptiler.attribution} />
  <MyMap setMap={setMap} />
  <MapEvents />
  <Marker key={index} ref={ index == props.targetedVehicle ? markerRef : null }
          position={{lat: val.latitude,  lng: val.longitude }}
          icon={OSMIcon}
          eventHandlers={{ click: () => popUpOpenBox(index) }} >
  <Popup closeButton={true}>
      A pretty CSS3 popup. <br /> Easily customizable.
  </Popup>
</MapContainer>

问题分析

  1. Map状态同步不及时:MyMap组件中的useEffect未依赖map,仅在初始化时同步map状态,后续map更新无法同步到父组件state。
  2. 闭包导致旧值引用:controlInfoWindow未用useCallback包裹且无依赖声明,函数内部引用的map、props可能为旧值,即使当前控制台显示map非null,函数内仍可能引用之前的null值。
  3. 判断顺序不合理:useEffect先调用controlInfoWindow()再判断map != null,若函数内引用的map是旧的null值,会直接触发报错。

解决方案

1. 修复Map状态同步逻辑

确保MyMap能实时同步map状态到父组件:

const MyMap = ({ setMap }) => {
  const map = useMap();

  useEffect(() => {
    setMap(map);
  }, [map, setMap]); // 添加依赖,确保map更新时同步

  return null;
};

2. 优化控制函数,解决闭包问题

用useCallback包裹函数并声明所有依赖:

import { useCallback } from 'react';

const controlInfoWindow = useCallback(() => {
  const marker = markerRef?.current;

  if (!map || !marker) {
    return false;
  }

  if (totalDeviceBtnClick) {
    return true;
  }
  if (props.filter) {
    return true;
  }
  if (
    props.routeControl === 0 &&
    props.areaFenceControl === 0 &&
    !props.showPopUpBox &&
    props.ambulanceTraumaMedLatLng.length === 0
  ) {
    return true;
  }
  if (
    props.routeControl === 1 &&
    props.areaFenceControl === 0 &&
    props.showPopUpBox
  ) {
    return true;
  }
  if (
    props.routeControl === 0 &&
    props.areaFenceControl === 1 &&
    props.showPopUpBox
  ) {
    return true;
  }
  if (
    props.routeControl === 1 &&
    props.areaFenceControl === 1 &&
    props.showPopUpBox
  ) {
    return true;
  }
  return false;
}, [
  map,
  markerRef,
  totalDeviceBtnClick,
  props.filter,
  props.routeControl,
  props.areaFenceControl,
  props.showPopUpBox,
  props.ambulanceTraumaMedLatLng.length
]);

3. 调整副作用判断顺序

先验证map和marker有效性,再执行控制逻辑:

useEffect(() => {
  const marker = markerRef?.current;
  if (map && marker && controlInfoWindow()) {
    marker.openPopup();
  }
}, [map, markerRef.current, controlInfoWindow]);

4. 额外检查

确认markerRef仅绑定到目标车辆的Marker组件,避免ref为空;同时确保Marker与Popup已正确关联,调用marker.openPopup()即可触发弹窗。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 20:16:16