繁体   English   中英

在 react-leaflet 上通过 useRef 数组移动一些标记

[英]On react-leaflet moving a few markers by useRef array

我正在尝试根据可拖动标记的 position 更改react-leaflet map 上的一些标记的 position。
这应该是在拖动可拖动标记时,在state上更改它会太慢,所以我选择用useRef来完成它到一个引用数组。
问题是r.leafletElement.setLatLng([lat, lng])线因为leafletElementundefined被压碎了。
(在其他尝试中,我只使用了一个标记而不是数组,并且useRef工作正常。)
非常感谢您的帮助,谢谢。

https://codepen.io/erangeva/pen/XWdyZzw

const { Map: LeafletMap, TileLayer, Marker, Popup, CircleMarker } = ReactLeaflet

const Simple = ({ nums }) => {
    const refs = React.useRef([]);
    if (refs.current.length !== nums.length) {
        refs.current = nums.map((_, i) => refs.current[i] || React.createRef());
    }
    return (
        <LeafletMap center={[51.505, -0.09]} zoom={13}>
            <TileLayer
                attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
                url='https://{s}.tile.osm.org/{z}/{x}/{y}.png'
            />
            <Marker position={[51.505, -0.09]} draggable={true}
                ondrag={(e) => {
                    refs.current.map((r, i) => {
                        const lat = e.target.getLatLng().lat;
                        const lng = e.target.getLatLng().lng + 0.01 * i;
                        r.leafletElement.setLatLng([lat, lng]);
                    })
                }}
            >
            </Marker>
            {
                nums.map(i =>
                    <Marker position={[51.505, -0.08 + 0.01 * i]}
                        ref={refs.current[i]}
                    >
                    </Marker>)
            }
        </LeafletMap>
    );

}


ReactDOM.render(<Simple nums={[0, 1, 2, 3, 4]} />, document.getElementById('container'))

在您的示例中, refs的初始化方式具有以下结构:

{
   current: [
       {current: Marker},
       ... 
   ]
} 

意味着底层标记 object 需要这样处理:

r.current.leafletElement.setLatLng([lat, lng]); 

这就是提供的错误首先发生的原因。


下面演示了另一种无需借助Refs即可操作标记列表的选项:

const MyMarkerList = ({ startPos }) => {

  const [positions, setPositions] = useState(calcPositions(startPos,4));
  
  function handleDrag(e) {
    const latLng = e.target.getLatLng();
    setPositions(calcPositions([latLng.lat, latLng.lng],4));
  }


  return (
    <>
    <Marker
        position={startPos}
        draggable={true}
        ondrag={(e) => {
          handleDrag(e);
        }}
      ></Marker>
      {positions.map((pos, i) => (
        <Marker key={i} position={pos}></Marker>
      ))}
    </>
  );
};

在哪里

function calcPositions(startPos,numOfPos){
  return [...Array(numOfPos)].map((v,i) => {
    return [startPos[0], startPos[1] + 0.01 * (i + 1)];
  });
}

用法

<Map center={startPos} zoom={13}>
      <TileLayer
        attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
        url="https://{s}.tile.osm.org/{z}/{x}/{y}.png"
      />
      <MyMarkerList startPos={startPos} />
  </Map>

您可以通过仅存储标记位置而不是标记 DOM 引用来实现这一点,标记 DOM 引用是存储在 memory 中的复杂且昂贵的对象。

这里初始化可拖动标记的position和要移动的标记。 第一个将是一个数组,后者是一个 arrays 的数组,其中包含要移动的标记的位置:

const [marker, setMarker] = useState([51.505, -0.09]);

const initialMarkersState = nums.map((n) => [51.505, -0.08 + 0.01 * n]);

const [markers, setMarkers] = useState(initialMarkersState);

在拖动事件侦听器上更改可拖动标记的 position,并使用 setMarker 和 setMarkers setState 方法更改所有其他标记的 position。

const handleMarkerDrag = (e) => {
    setMarker(e.latlng);
    const lat = e.target.getLatLng().lat;
    const lng = e.target.getLatLng().lng + 0.01;
    setMarkers((prevState) => {
      const newState = [...prevState];
      nums.forEach((n) => {
        newState[n] = [lat, lng + 0.01 * n];
      });
      return newState;
    });
  };

最后通过遍历标记数组来渲染标记。

{markers.map((position, i) => (
    <Marker position={position} key={i} icon={icon}></Marker>
))}

演示

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM