React页面中Google Map折线切换焦点后重置问题求助
问题描述
React页面分为上下两部分:上半部分是表单,下半部分是Google Map组件。在地图中添加Polyline后,左键点击添加点、右键点击删除点或拖拽折线时,路径更新正常;但操作表单区域的输入框/按钮后,再尝试添加/删除折线点,会创建新折线(删除操作因无点可删失效)。
现有核心代码如下:
事件处理与地图渲染代码
const addLatLng = (event) => { const path = poly.getPath(); path.push(event.latLng); } const removeVertex = (vertex) => { let path = poly.getPath(); path.removeAt(vertex) } // eslint-disable-next-line no-undef google.maps.event.addListener(poly, 'rightclick', function (event) { if (event.vertex === undefined) { return; } else { removeVertex(event.vertex) } })
<div style={{ height: '100vh' }}> <GoogleMap center={center} zoom={3} onLoad={(map) => setMap(map)} mapContainerStyle={{ width: '100%', height: '100%' }} onClick={(event) => { !showInputForLink && addLatLng(event) }} > </GoogleMap> </div>
地图与折线声明代码
const { isLoaded } = useJsApiLoader({ googleMapsApiKey: ct.MAPS_API_KEY, libraries: ['drawing, places'] }) // eslint-disable-next-line no-undef const [map, setMap] = useState(/** @type google.maps.Map */(null)) const poly = new google.maps.Polyline({ strokeColor: '#160BB9', strokeOpacity: 1.0, strokeWeight: 3, editable: true, }); poly.setMap(map)
问题原因
每次操作表单触发组件重新渲染时,const poly = new google.maps.Polyline(...)都会重新执行,创建全新的Polyline实例,之前的实例和路径数据完全丢失。同时,初始渲染时map为null,poly.setMap(map)不会生效;地图加载后组件重渲染,又会重复创建新实例并挂载到地图上,导致多条折线共存,旧实例的事件监听失效。
解决方案
1. 用useRef持久化Polyline实例
useRef可以在组件多次渲染间保存同一个实例,不会随重渲染重新创建:
// 替换原有的poly声明 const polyRef = useRef(null);
2. 在地图加载后初始化折线与事件监听
仅当地图加载完成时,才创建并挂载Polyline,避免map为null的情况,同时把事件监听绑定到持久化的实例上:
<GoogleMap center={center} zoom={3} onLoad={(mapInstance) => { setMap(mapInstance); // 初始化折线并保存到ref const poly = new google.maps.Polyline({ strokeColor: '#160BB9', strokeOpacity: 1.0, strokeWeight: 3, editable: true, }); poly.setMap(mapInstance); polyRef.current = poly; // 绑定右键删除事件 google.maps.event.addListener(poly, 'rightclick', function (event) { if (event.vertex === undefined) return; removeVertex(event.vertex); }); }} mapContainerStyle={{ width: '100%', height: '100%' }} onClick={(event) => { !showInputForLink && addLatLng(event) }} > </GoogleMap>
3. 修改事件处理函数,使用ref中的实例
确保操作的是同一个持久化的折线实例:
const addLatLng = (event) => { if (!polyRef.current) return; // 避免实例未初始化时操作 const path = polyRef.current.getPath(); path.push(event.latLng); } const removeVertex = (vertex) => { if (!polyRef.current) return; const path = polyRef.current.getPath(); path.removeAt(vertex); }
4. 组件卸载时清理资源(可选)
避免内存泄漏,卸载时移除折线和事件监听:
useEffect(() => { return () => { if (polyRef.current) { google.maps.event.clearInstanceListeners(polyRef.current); polyRef.current.setMap(null); } }; }, []);
关键说明
不需要替换为地图内声明的Poly组件,核心是让Polyline实例在组件重渲染时保持唯一,通过useRef实现持久化,同时把实例初始化和事件绑定逻辑放到地图加载的回调中,避免重复执行。
内容的提问来源于stack exchange,提问作者Calin Onaca
相关产品推荐
相关产品推荐

