我正在使用react-leaflet
显示带有从API加载的动态标记的地图。到目前为止,我一直在将标记加载到渲染器中,但是我意识到,每次更改任何内容(例如缩放,位置)时,渲染都不必要地重新渲染整个Leaflet Map。我想我可以删除缩放和位置状态并为此调用本地Leaflet函数,但最终我需要在初始渲染后加载我的数据,至少可以进行第二次不必要的渲染。 React是否真的设计成是首选方式?
function MyMap() {
const [markers, setMarkers] = useState([]);
useEffect(() => {
console.log('useEffect');
getMyData().then(a => {
console.log('data load');
setMarkers(a);
});
}, []);
console.log('map render');
return (
<Map id='map' className='map' center={[52, 0]} zoom={6}>
<TileLayer
url='https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
/>
<LayerGroup>
{markers.map(a => {
return (
<Marker
key={a._id}
position={[a.location.latitude, a.location.longitude]}
icon={myIcon}
/>
);
})}
</LayerGroup>
</Map>
);
}
控制台输出:
map render
useEffect
data load
map render
我很想通过以普通的Leaflet方式动态添加标记来解决此问题:
L.marker([50.5, 30.5]).addTo(map);
但是,这在react-leaflet
中显得不平凡。在寻找如何动态添加标记的过程中,我遇到了React Leaflet:动态添加标记,特别是top answer建议不要这样做。关联的jsfiddle会为每次点击重新呈现整个地图。也许还好吗?
为了防止在添加标记后重新渲染地图,可以应用以下更改列表:
a]中处于MyMap
状态的markers
(父级)组件中,保持跟踪only从数据源加载的标记
注意:一旦在此组件中单击地图,
markers
状态将不会更新
function MyMap() {
const [markers, setMarkers] = useState([]);
useEffect(() => {
console.log("useEffect");
getMyData().then((data) => {
console.log("data load");
setMarkers(data);
});
}, []);
console.log("map render");
return (
<Map id="map" className="map" center={[52, 0]} zoom={4}>
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
/>
<MyLayer defaultMarkers={markers} />
</Map>
);
}
b)引入状态为markers
的单独的(子)组件来跟踪从数据源加载的标记(使用通过props
传递的默认值进行设置),以及在地图click
事件上添加的标记:
function MyLayer(props, ref) {
const { defaultMarkers } = props;
const [markers, setMarkers] = useState(defaultMarkers);
const mapProps = useLeaflet();
const addMarker = useCallback((e) => {
const newMarker = {
location: e.latlng,
};
console.log(newMarker);
setMarkers((existingMarkers) => [...existingMarkers, newMarker]);
}, []);
useEffect(() => {
setMarkers(defaultMarkers);
mapProps.map.on('click',addMarker)
}, [addMarker,mapProps,defaultMarkers]);
return (
<LayerGroup>
{markers.map((marker, idx) => {
return (
<Marker
key={idx}
position={[marker.location.lat, marker.location.lng]}
/>
);
})}
</LayerGroup>
);
}
这里是demo