如何在模态窗口首次渲染/启动时获取可用的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
相关产品推荐
相关产品推荐

