react-leaflet - “React 方式”真的是定期重新渲染整个 react-leaflet 组件吗?
问题描述
我react-leaflet
用来显示带有从 API 加载的动态标记的地图。到目前为止,我一直在渲染中加载标记,但我意识到每次发生任何变化(例如缩放、位置)时,这都会不必要地重新渲染整个传单地图。我想我可以删除我的缩放和位置状态并为此调用本机 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:动态添加标记,特别是建议不应该这样做的最佳答案。关联的 jsfiddle 会为每次点击重新渲染整个地图。也许这很好?
解决方案
为了防止在添加标记后重新渲染地图,可以应用以下更改列表:
a)在状态的MyMap
(父)组件中仅markers
跟踪从数据源加载的标记
注意:
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>
);
}
这是一个演示
推荐阅读
- python - 从空格上的列中删除行
- python - 将数组的每个元素除以另一个数组的每个元素
- node.js - 带有 Babel 和 Typescript 的 Node.js 应用程序中的 ES6 导入语法
- java - NewPooledConnection 泄漏
- c# - 限制对文件夹中文件的 URL 访问 - Azure 上的 ASP.NET MVC
- api - 如何在 Flutter 中将图像从 API 设置为轮播
- c# - 字符串未被识别为有效的日期时间,2019 年 7 月 11 日
- r - 如何按 ID 对行进行分组并计算平均值和 IQR
- node.js - 为项目创建 .env 文件的正确方法
- javascript - 在另一个二维数组中复制洗牌数组的问题