React18多子页面渲染react-leaflet的MapContainer报已初始化错误
react-leaflet 4.0 + React 18 页面切换报「Map container is already initialized」修复方案
报错原因
该问题不是配置遗漏导致,核心原因是react-leaflet 4.0.0版本在React 18的页面路由切换场景下,MapContainer组件卸载时没有正确清理DOM节点上绑定的Leaflet地图实例。当同个地图DOM容器被复用时,再次执行地图初始化逻辑就会抛出容器已被初始化的错误。
首次进入详情页时DOM节点是全新的,无历史绑定实例因此加载正常;返回列表后再次进入其他详情页时,复用的DOM节点上残留了之前的地图实例,就会触发报错。
可落地修复方案
按优先级从高到低选择即可:
- 方案1:给
MapContainer绑定和页面唯一标识关联的key,强制组件切换时完全重建
给组件传入当前详情页的唯一ID(比如事件ID)作为key,React识别到key变化时会直接销毁旧组件、挂载全新组件,不会复用残留实例的DOM节点,代码改动最小:export function MapWithPoints(props: Props) { const { points, eventId } = props // 从props传入当前事件的唯一标识 return ( <MapContainer key={eventId} // 新增该行,绑定唯一key scrollWheelZoom={false} style={{ height: 300, width: '100vw' }} > <InnerMap points={points} /> </MapContainer> ) } - 方案2:手动在组件卸载时销毁地图实例
如果加key后仍有报错(比如开启React 18严格模式的开发环境双执行场景),可以通过ref拿到地图实例,在组件卸载生命周期里主动调用销毁方法,彻底清理残留实例:import { useRef, useEffect } from 'react' export function MapWithPoints(props: Props) { const { points } = props const mapRef = useRef(null) useEffect(() => { // 组件卸载时执行清理 return () => { if (mapRef.current) { mapRef.current.remove() } } }, []) return ( <MapContainer scrollWheelZoom={false} style={{ height: 300, width: '100vw' }} ref={(mapInstance) => { if (mapInstance) mapRef.current = mapInstance }} > <InnerMap points={points} /> </MapContainer> ) } - 方案3:升级react-leaflet版本
react-leaflet在4.2.0及以上版本修复了React 18严格模式下的实例清理问题,如果项目允许升级依赖,直接升级到最新稳定版也可以解决该问题。
内容的提问来源于stack exchange,提问作者TBowmo
相关产品推荐
相关产品推荐

