React-Leaflet中flyTo函数使用动态position参数无法正常跳转地图位置
React-Leaflet中flyTo函数使用动态position参数无法正常跳转地图位置
嘿,我看你碰到的问题是:当选中不同标记更新position后,点击按钮调用map.flyTo却还是跳转到旧位置对吧?这其实是JavaScript闭包陷阱搞的鬼,咱们来一步步解决它~
问题根源
你当前的代码里,handleLocateButton函数是在组件第一次渲染时创建的,它捕获了当时的position值。而useEffect的依赖只有map,所以当父组件传递的position更新时,这个useEffect不会重新执行,控件也不会重新创建,handleLocateButton里的position始终是最初的那个旧值,自然跳不到新位置啦。
解决方案:跟踪最新的position值
这里有两种靠谱的解决方式,推荐第二种更高效的:
方式1:更新useEffect依赖(简单但有小开销)
直接把position加入useEffect的依赖数组,这样每次position变化时,都会重新创建并添加地图控件,新的handleLocateButton会捕获最新的position:
// 修改useEffect的依赖项 useEffect(() => { // ... 原有控件创建代码 }, [map, position]); // 加入position
不过这种方式每次position变化都会销毁重建控件,虽然能解决问题,但有点没必要的性能损耗。
方式2:用useRef跟踪最新值(更优雅高效)
用useRef来保存最新的position,它的current属性是可变的,不会触发组件重渲染,而且能让handleLocateButton每次调用都拿到最新值:
修改后的完整代码:
import {useEffect, useRef} from "react"; import {createRoot} from "react-dom/client"; import {useMap} from "react-leaflet"; import L from "leaflet"; import locateIcon from '../assets/my-location.svg' import routeIcon from '../assets/route.svg' import '../components/IconButton.css' export default function CustomControls({position}) { // 用ref保存最新的position,初始值为传入的position const positionRef = useRef(position); // 每当position更新时,同步更新ref的current值 useEffect(() => { positionRef.current = position; }, [position]); // Add icons const LocateControlIcon = () => <img src={locateIcon}/>; const RouteControlIcon = () => <img src={routeIcon}/>; const map = useMap(); // Functionality buttons function handleLocateButton() { console.log('Fly to: ' + positionRef.current); // 这里使用ref的current值,确保是最新的position map.flyTo(positionRef.current); } function handleRouteButton() { alert('Button clicked!'); } useEffect(() => { const CustomControl = L.Control.extend({ position: "topright", onAdd: () => { const container = L.DomUtil.create('div', 'custom-control'); container.style.margin = '16px 16px 0 0'; const locateButton = L.DomUtil.create('button', 'icon-button', container); locateButton.onclick = handleLocateButton; const routeButton = L.DomUtil.create('button', 'icon-button', container); routeButton.style.margin = '8px 0 0 0'; routeButton.onclick = handleRouteButton; // Render icons in the buttons createRoot(locateButton).render(<LocateControlIcon/>); createRoot(routeButton).render(<RouteControlIcon/>); L.DomEvent.disableClickPropagation(container); return container; }, }); const controlInstance = new CustomControl(); map.addControl(controlInstance); return () => { map.removeControl(controlInstance); }; }, [map]); return null; }
为什么这样能行?
positionRef的current属性会在每次position更新时同步最新值,而且这个过程不会触发组件重渲染。handleLocateButton每次被调用时,都会读取positionRef.current,也就是最新的坐标值,自然就能正确跳转到选中标记的位置了。- 地图控件只需要创建一次,避免了不必要的销毁重建,性能更友好。
备注:内容来源于stack exchange,提问作者Northbret
相关产品推荐
相关产品推荐

