在 react-leaflet 上通过 useRef 数组移动一些标记
On react-leaflet moving a few markers by useRef array
我正在尝试根据可拖动标记的位置更改 react-leaflet
地图上一些标记的位置。
这应该是在拖动可拖动标记时,在 state
上更改它会太慢,所以我选择用 useRef
来做一个引用数组。
问题是 r.leafletElement.setLatLng([lat, lng])
线被压碎了,因为 leafletElement
是 undefined
。
(在其他尝试中,我只使用了一个标记而不是数组,并且 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='© <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'))
您可以通过仅存储 marker positions 而不是 markerDOM 引用来实现此目的 存储在内存中的对象既复杂又昂贵。
这里初始化可拖动标记的位置和要移动的标记。第一个将是一个数组,后者是一个包含要移动的标记位置的数组:
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);
在拖动事件侦听器上,使用 setMarker 和 setMarkers setState 方法更改可拖动标记的位置并更改所有其他标记的位置。
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>
))}
在您的示例中,refs
的初始化方式具有以下结构:
{
current: [
{current: Marker},
...
]
}
意味着底层标记对象需要这样处理:
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='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.osm.org/{z}/{x}/{y}.png"
/>
<MyMarkerList startPos={startPos} />
</Map>
我正在尝试根据可拖动标记的位置更改 react-leaflet
地图上一些标记的位置。
这应该是在拖动可拖动标记时,在 state
上更改它会太慢,所以我选择用 useRef
来做一个引用数组。
问题是 r.leafletElement.setLatLng([lat, lng])
线被压碎了,因为 leafletElement
是 undefined
。
(在其他尝试中,我只使用了一个标记而不是数组,并且 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='© <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'))
您可以通过仅存储 marker positions 而不是 markerDOM 引用来实现此目的 存储在内存中的对象既复杂又昂贵。
这里初始化可拖动标记的位置和要移动的标记。第一个将是一个数组,后者是一个包含要移动的标记位置的数组:
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);
在拖动事件侦听器上,使用 setMarker 和 setMarkers setState 方法更改可拖动标记的位置并更改所有其他标记的位置。
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>
))}
在您的示例中,refs
的初始化方式具有以下结构:
{
current: [
{current: Marker},
...
]
}
意味着底层标记对象需要这样处理:
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='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.osm.org/{z}/{x}/{y}.png"
/>
<MyMarkerList startPos={startPos} />
</Map>