如何仅在点击按钮时触发react-leaflet的useMap钩子
问题描述
我在react-leaflet地图上实现简单的移动控制,按下按钮后让地图“飞至”一组预设坐标。通过useMap()钩子在子组件中访问Map实例,代码如下:
NavigateToMarker.jsx
import { useMap } from "react-leaflet"; export default function NavigateToMarker({position}) { const map = useMap(); map.flyTo(position, 13) return null }
MainMap.jsx
import NavigateToMarker from './NavigateToMarker'; export default function MainMap() { const [position, setPosition] = React.useState([51.607642, -0.129303]) const handleClick = (position) => { setPosition(position) } return ( <> <MapContainer> <TileLayer /> <GeoJSON data={geoJsonData} /> <NavigateToMarker position={position} /> </MapContainer> <Button onClick={() => handleClick([52.309611, -0.139303])}>Fly To Position</Button> </> ) }
按钮能正常触发地图飞至目标位置,但每次MainMap组件渲染时,NavigateToMarker里的map.flyTo都会自动执行。试过把按钮放进NavigateToMarker,但它在MapContainer内部无法显示,也不方便做CSS网格布局。想知道怎么让map.flyTo只在点击按钮时执行?
解决方案
方法1:用useEffect监听触发状态
给NavigateToMarker新增一个trigger属性,仅当trigger状态变化时才执行飞行动作,避免组件渲染或position更新就触发:
NavigateToMarker.jsx
import { useMap, useEffect } from "react-leaflet"; export default function NavigateToMarker({ position, trigger }) { const map = useMap(); useEffect(() => { if (trigger) { map.flyTo(position, 13); } }, [map, position, trigger]); return null; }
MainMap.jsx新增触发状态,点击按钮时更新trigger:
import NavigateToMarker from './NavigateToMarker'; import { useState } from 'react'; export default function MainMap() { const [position, setPosition] = useState([51.607642, -0.129303]); const [flyTrigger, setFlyTrigger] = useState(false); const handleClick = (targetPosition) => { setPosition(targetPosition); setFlyTrigger(prev => !prev); }; return ( <> <MapContainer> <TileLayer /> <GeoJSON data={geoJsonData} /> <NavigateToMarker position={position} trigger={flyTrigger} /> </MapContainer> <Button onClick={() => handleClick([52.309611, -0.139303])}>Fly To Position</Button> </> ); }
方法2:直接在MainMap中获取Map实例
如果逻辑简单,没必要单独拆分子组件,直接在MainMap内部获取Map实例,点击按钮时直接调用方法:
MainMap.jsx
import { useState } from 'react'; import { MapContainer, TileLayer, GeoJSON, useMap } from 'react-leaflet'; const MapController = ({ onMapReady }) => { const map = useMap(); useState(() => { onMapReady(map); }, [map, onMapReady]); return null; }; export default function MainMap() { const [mapInstance, setMapInstance] = useState(null); const handleClick = (targetPosition) => { mapInstance?.flyTo(targetPosition, 13); }; return ( <> <MapContainer> <TileLayer /> <GeoJSON data={geoJsonData} /> <MapController onMapReady={setMapInstance} /> </MapContainer> <Button onClick={() => handleClick([52.309611, -0.139303])}>Fly To Position</Button> </> ); }
方法3:条件渲染NavigateToMarker
只有点击按钮后才渲染NavigateToMarker,执行飞行动作后再卸载组件:
MainMap.jsx
import NavigateToMarker from './NavigateToMarker'; import { useState } from 'react'; export default function MainMap() { const [targetPosition, setTargetPosition] = useState(null); const handleClick = (position) => { setTargetPosition(position); setTimeout(() => setTargetPosition(null), 100); }; return ( <> <MapContainer> <TileLayer /> <GeoJSON data={geoJsonData} /> {targetPosition && <NavigateToMarker position={targetPosition} />} </MapContainer> <Button onClick={() => handleClick([52.309611, -0.139303])}>Fly To Position</Button> </> ); }
NavigateToMarker保持原代码即可,仅在点击按钮时渲染执行一次map.flyTo,之后自动卸载。
内容的提问来源于stack exchange,提问作者AmazingBergkamp
相关产品推荐
相关产品推荐

