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

如何在模态窗口首次渲染/启动时获取可用的Map Ref对象

解决react-map-gl在Dialog首次渲染时mapRef为null的问题

这个问题我之前也碰到过!核心原因是Dialog属于条件渲染组件:当你点击按钮把open设为true后,Map组件才开始挂载,但你的useEffect只监听了rowData的变化——这时候要么rowData没变化导致useEffect不触发,要么触发时Map还没完成初始化,所以mapRef.current还是null。

给你两个靠谱的解决方案:

方案一:利用react-map-gl的onLoad事件(推荐)

react-map-gl提供了onLoad回调,会在地图完全加载并初始化完成后触发,这时候你能确保拿到有效的地图实例。直接在这个回调里处理地图定位逻辑就好:

export default function MapDialog() {
  // ... 其他状态和ref保持不变

  const handleMapLoad = useCallback((map) => {
    // 地图加载完成后,直接设置中心坐标
    map.setCenter({ lat: rowData?.laty, lng: rowData?.longx });
  }, [rowData]);

  return (
    <>
      <button onClick={handleClickOpen}> open map </button>
      <Dialog onClose={handleClose} aria-labelledby="customized-dialog-title" open={open} PaperProps={{ sx: { minWidth: 500, minHeight: 400 } }} >
        <DialogTitle id="customized-dialog-title" onClose={handleClose}> Map </DialogTitle>
        <DialogContent dividers>
          <MapGl
            ref={mapRef}
            initialViewState={viewport}
            mapStyle="mapbox://styles/mapbox/streets-v11"
            style={{ height: "calc(100vh - 64px)", width: "100%" }}
            onViewStateChange={(viewState) => setViewport(viewState)}
            mapboxAccessToken="pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4M29iazA2Z2gycXA4N2pmbDZmangifQ.-g_vE53SD2WrJ6tFX7QHmA"
            attributionControl={true}
            interactive={true}
            showCompass={true}
            onLoad={handleMapLoad} // 新增onLoad回调
          >
            <NavigationControl />
            <Marker
              className="marker"
              key={rowData?.laty}
              longitude={rowData?.longx}
              latitude={rowData?.laty}
              offsetTop={(-viewport.zoom * 5) / 2}
              anchor="bottom"
              style={{ cursor: "pointer" }}
            >
              <svg data-name="marker" width="20" height="48">
                <ellipse cx="10" cy="27" rx="9" ry="5" fill="#c4c4c4" opacity=".3" />
                <path data-name="shadow" fill="#bfbfbf" d="M10 32c5 0 9-2.2 9-5s-4-5-9-5-9 2.2-9 5 4 5 9 5Z" fillRule="evenodd" opacity=".3" />
                <path fill="#4264fb" stroke="#314ccd" strokeWidth=".5" d="M19.25 10.4a13.066 13.066 0 0 1-1.46 5.223 41.528 41.528 0 0 1-3.247 5.549 71.377 71.377 0 0 1-4.542 5.945l-.217-.258a73.206 73.206 0 0 1-4.327-5.725 42.268 42.268 0 0 1-3.246-5.553A12.978 12.978 0 0 1 .75 10.4 9.466 9.466 0 0 1 10 .75a9.466 9.466 0 0 1 9.25 9.65Z" />
                <path fill="#fff" stroke="#314ccd" strokeWidth=".5" d="M13.55 10A3.55 3.55 0 1 1 10 6.45 3.548 3.548 0 0 1 13.55 10Z" />
                <path fill="none" d="M0 0h20v48H0z" />
              </svg>
            </Marker>
          </MapGl>
        </DialogContent>
      </Dialog>
    </>
  );
}

方案二:调整useEffect的依赖项并增加状态判断

如果不想用onLoad,可以把open加入useEffect的依赖数组,确保Dialog打开时触发逻辑,同时判断地图实例是否就绪:

useEffect(() => {
  // 仅当Dialog打开且rowData存在时执行
  if (open && rowData && mapRef.current) {
    mapRef.current.setCenter({ lat: rowData.laty, lng: rowData.longx });
  }
}, [open, rowData]);

额外优化建议

  • 把rowData改成组件状态(比如const [selectedRow, setSelectedRow] = useState(null)),这样当表格行点击时更新状态,onLoad或者useEffect就能自动响应坐标变化。
  • 关闭Dialog时,可以重置viewport到初始值,避免下次打开地图位置残留。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 13:49:06