reactjs - React-Leaflet - 更新存储在状态中的 Circle 对象,或者优化 Circles 加载速度
问题描述
我正在尝试创建一个包含大量 Circle 对象的地图。这些圆圈的颜色将根据用户输入而改变。很多颜色可以同时变化,我想尽快呈现变化。
为了节省每次用户更改某些内容并重新渲染地图时创建 Circles 的时间,我考虑将 Circle 对象存储在 state 中的数组中。然后,当用户更改某些内容时,我想更新 Circles 的属性,但不使用复制方法等(因为它与只创建一次 Circle 对象的想法相矛盾)。
我考虑过创建一个存储颜色的并行数组,该数组将由用户更新,并在每个 Circle 对象的 pathOptions 中存储对此数组中并行位置的引用,但我不确定如何执行此操作。
或者,我很高兴听到有关如何优化速度的任何其他指示。
基本版本,应用程序从数组中正确加载圆圈,颜色是静态的:
import locations from "../locations.json"
function Map(props){
const [circlesArray, setCirclesArray] = useState([])
useEffect(() => { //initializes the circlesArray
let tempCirclesArray = []
locations.map(location => {
let position = [location.coordinates[1], location.coordinates[0]]
tempCirclesArray.push(
<CircleMarker center={position} radius={4}
pathOptions={
color: "red",
fillColor: "red"
} //here pathOptions is predetermined
/>
)
})
setCirclesArray(tempCirclesArray)
}, [])
return(
<div>
<div id="mapid" ref={mapRef}>
<button onClick={clickTest}>helno</button>
<MapContainer center={defaultPositon} zoom={mapZoom} scrollWheelZoom={true}>
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
//map and display the Circle objects
{
circlesArray.map(circle => {
return(circle)
})
}
</MapContainer>
</div>
</div>
)
解决方案
将这些CircleMarker
组件保持在状态根本不理想。来自 react-leaflet 文档:
默认情况下,这些道具应被视为不可变的,只有在此页面中明确记录为可变的道具才会在更改时影响 Leaflet 元素。
更改这些道具不会重新渲染它们。
这可以通过使用 refs 做得更好。我刚刚在这里回答了一个问题:如何在地图加载时打开特定的弹出窗口?
. 您可以看到有关如何结合 refs 和 state 以到达底层传单元素的详细说明。在您的情况下,最好不要将所有这些<CircleMaker>
组件都保存在状态变量中。直接在您的组件中使用 a locations.map
,并在该映射中,将所有引用保存到一个对象:
import locations from "../locations.json"
const MyMapComponent = {
const circleRefs = React.useRef()
return (
<MapContainer {...MapContainerProps}>
<TileLayer />
{locations.map(location => {
let position = [location.coordinates[1], location.coordinates[0]]
return (
<CircleMarker
preferCanvas
center={position}
radius={4}
pathOptions={...options_you_want}
ref={(ref) => {
circleRefs.current[location.id] = ref;
}}
/>
)
})}
</MapContainer>
)
}
现在您有一个对象circleRefs
,其中包含一个对象。该对象的键是每个对象的唯一 id 值location
,该值是底层传单L.circleMarker实例。有了它,您可以在任何这些 refs 上调用传单的setStyle方法。例如,circleRefs['some-unique-id'].setStyle({ fillColor: 'red' })
将设置该引用的样式。
通过这种方式,您可以更改这些圆圈的颜色,而无需强制重新渲染。这可以一次在很多圈子上完成,而不会对性能造成巨大影响——而不是卸载(并删除)圈子组件,传单的内部结构会重新着色 svg。
我还添加了preferCanvas
道具,对于任何扩展 L.path(包括 L.circleMarker)的东西,它选择使用画布而不是 svgs。对于大量项目,这也有助于提高性能。
推荐阅读
- c# - 为集成测试播种 WebApplicationFactory 不保存并给出 404
- python-3.x - 如何将这种类型的“字典”转换为数据框?
- java - selenium 根据索引位置获取 li 元素并单击复选框
- html - 引导显示无法在手机上进行生产
- java - Java Cucumber 自定义对象类型参数
- javascript - 通过正则表达式 WordPress 修改菜单项的第一个字母不起作用
- android - 外部图像未在 Android 中显示
- java - Java string.split 与 C# Regex.split - 限制为一定数量的字段
- python - Dask 数据框的值
- javascript - Raspberry Pi Zero W 上的 Node.js,依赖项不会自动下载