React-leaflet 性能问题,防止 GeoJSON 重新渲染

React-leaflet performance issue, prevent GeoJSON re-render

我有以下问题:

我想使用 react-leafletGeoJSON 组件创建一个简单的等值线图。我还想要一个工具提示,在悬停在 GeoJSON 功能上时显示一个值。问题是性能。可以在此处找到 CodePen 示例:https://codepen.io/timester-the-typescripter/pen/gOXGKOY

我将事件处理程序附加到每个 GeoJSON 功能,并在我的“主”组件中设置一个状态变量来保存当前悬停区域的值。

const [selected, setSelected] = React.useState(null);

我的工具提示依赖于该状态变量来显示其值。因为每次鼠标悬停事件都会导致主要组件状态发生变化,所以 GeoJSON 组件会一直重新渲染。这在 CodePen 示例中不是一个大问题,但不幸的是对于完整的世界地图。

我假设状态变化导致了这个,因为如果我注释掉 2 setSelected 行(CodePen 中的第 55 行和第 67 行),重新呈现(调用 createGeoJSON )停止,事件处理程序 运行 快很多,如下面的分析器图片所示。

Mouseout 事件状态改变:

带有状态更改的 Mouseout 事件被注释掉:

我尝试了很多解决方案都没有成功。例如,我认为我无法记住 GeoJSON 组件,因为 Tooltip 必须是它的子组件,这取决于主要组件的状态。

将来我想根据悬停状态变量添加更多组件,例如图例等。也许该变量也会比简单数字更复杂。

我在这里有什么选择?我有另一个关于这个的stackowerflow问题,但后来我没有完全理解这个问题,所以不是很专注。我正在考虑在 Angular 中重写它。在这个问题出现之前,我发现 react 和 react-leaflet 非常好用。

我从这个 reddit 评论中得到了帮助 https://www.reddit.com/r/reactjs/comments/std46f/comment/hx3yq34/?utm_source=share&utm_medium=web2x&context=3

我基于此应用的解决方案是不将Tooltip作为子组件,而是在onEachFeature方法中为每一层绑定一个tooltip

const onEachFeature = useCallback((feature, layer) => {
    layer.bindTooltip(feature.properties.COUNT, {sticky: true});
    ...
    

这样我也可以将 GeoJSON 组件包装在 useMemo() 中,因为不再依赖于 selected 状态。我还将 styleonEachFeature 函数包装在 useCallback().

这个组合解决了问题!

问题是当前您正在通过状态在每次鼠标悬停时使用适当的工具提示重新创建地图。相反,您应该在创建地图时使用 layer.bindTooltip() 绑定所有工具提示。这将允许您只 show/hide 它们而无需再次重新创建地图,因为它们已经创建并且它们的创建将不依赖于状态。

请参阅此 github 问题以了解弹出窗口的示例(但工具提示的逻辑应该相同):https://github.com/PaulLeCam/react-leaflet/issues/33