React Leaflet地图加载时触发定位事件出现TypeError问题
问题描述
在React Leaflet中尝试在地图加载时触发定位功能,却遭遇TypeError: latlng is undefined错误。将触发逻辑改为useMapEvents的点击事件时能正常运行,但使用useMapEvents的load事件或通过useEffect实现加载时触发,均会出现相同错误。控制台能输出正确的坐标数组,但错误依然存在。
错误栈
Uncaught TypeError: latlng is undefined project Projection.SphericalMercator.js:24 latLngToPoint CRS.js:28 project Map.js:982 latLngToLayerPoint Map.js:1004 _project CircleMarker.js:72 _reset Path.js:139 onAdd Path.js:85 _layerAdd Layer.js:114 whenReady Map.js:1477 addLayer Layer.js:172 addLayer layer.js:9 React 8 workLoop scheduler.development.js:266 flushWork scheduler.development.js:239 performWorkUntilDeadline scheduler.development.js:533 ...etc
组件代码
import { useState, useEffect } from "react"; import { useMap, useMapEvents, CircleMarker } from "react-leaflet"; const CurrentLocation = () => { const [position, setPosition] = useState(null); const map = useMap(); useEffect(() => { map.locate().on("locationfound", (e) => { const pos = [e.latlng.lat, e.latlng.lng]; console.log(pos); setPosition(pos); map.flyTo(pos, map.getZoom()); }); }, [map]); return position === null ? null : ( <CircleMarker position={position}></CircleMarker> ); }; export default CurrentLocation;
主地图调用代码
... import CurrentLocation from "../CurrentLocation/CurrentLocation"; const MainMap = (props) => { ... return ( <div> <MapContainer style={{ height: "100vh", width: "100vw" }} zoom={12} center={centerOfMap} > <TileLayer attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" /> <CurrentLocation /> ... </MapContainer> </div>
解决方案
问题根源在于两个潜在点:一是定位事件触发时地图可能未完全就绪,导致CircleMarker渲染时出现坐标解析异常;二是直接使用数组作为position属性值,可能在Leaflet内部处理时出现类型兼容问题。以下是修复后的代码:
import { useState, useEffect } from "react"; import { useMap, CircleMarker } from "react-leaflet"; import L from "leaflet"; const CurrentLocation = () => { const [position, setPosition] = useState(null); const map = useMap(); useEffect(() => { // 定义定位成功后的处理函数 const handleLocationFound = (e) => { // 使用Leaflet的LatLng对象创建坐标,确保类型兼容 const pos = L.latLng(e.latlng.lat, e.latlng.lng); console.log(pos); setPosition(pos); map.flyTo(pos, map.getZoom()); }; // 等待地图完全就绪后再执行定位 const handleMapReady = () => { map.locate().on("locationfound", handleLocationFound); }; map.whenReady(handleMapReady); // 清理事件监听,避免内存泄漏 return () => { map.off("locationfound", handleLocationFound); map.off("ready", handleMapReady); }; }, [map]); return position ? <CircleMarker position={position} /> : null; }; export default CurrentLocation;
关键修复点
- 确保地图就绪后执行定位:通过
map.whenReady()方法,等待地图完全初始化后再触发定位逻辑,避免在地图未就绪时添加CircleMarker。 - 使用Leaflet原生LatLng对象:将坐标数组转换为Leaflet的
LatLng对象传递给CircleMarker的position属性,避免类型解析错误。 - 添加事件清理函数:在
useEffect的返回函数中移除事件监听,防止组件卸载后仍触发事件导致内存泄漏。
内容的提问来源于stack exchange,提问作者Redact0r
相关产品推荐
相关产品推荐

