Merge pull request #1188 from nowcommunity/codex/1056-web-freezing-locality-map

fix: Lazy load country polygons to prevent UI freeze (#1056)
This commit is contained in:
Kari Lintulaakso
2026-05-29 16:20:11 +03:00
committed by GitHub
+38 -14
View File
@@ -1,7 +1,6 @@
import { useGetLocalityDetailsQuery } from '../../redux/localityReducer'
import { useState, useEffect, useRef } from 'react'
import 'leaflet/dist/leaflet.css'
import { countryPolygons } from '../../country_data/countryPolygons.ts'
import L, { LatLngExpression } from 'leaflet'
import { SimplifiedLocality } from '../../shared/types/data.js'
import { skipToken } from '@reduxjs/toolkit/query'
@@ -25,6 +24,7 @@ export const LocalitiesMap = ({ localities, isFetching }: Props) => {
const [selectedLocality, setSelectedLocality] = useState<string | null>(null)
const mapRef = useRef<HTMLDivElement | null>(null)
const [map, setMap] = useState<L.Map | null>(null)
const borderLayerRef = useRef<L.LayerGroup | null>(null)
const [isOpen, setIsOpen] = useState(false)
const [localityDetailsIsOpen, setLocalityDetailsIsOpen] = useState(false)
const [clusteringEnabled, setClusteringEnabled] = useState(true)
@@ -34,6 +34,26 @@ export const LocalitiesMap = ({ localities, isFetching }: Props) => {
selectedLocality ?? skipToken
)
// Lazy load country polygons to avoid blocking the main thread with 4.4MB of data
const [countryPolygons, setCountryPolygons] = useState<unknown[] | null>(null)
useEffect(() => {
let mounted = true
// Dynamically import country polygons to avoid blocking on initial load
void import('../../country_data/countryPolygons.ts')
.then(module => {
if (mounted) setCountryPolygons(module.countryPolygons)
})
.catch(() => {
if (mounted) setCountryPolygons([])
})
return () => {
mounted = false
}
}, [])
useEffect(() => {
if (!mapRef.current) return
@@ -57,21 +77,9 @@ export const LocalitiesMap = ({ localities, isFetching }: Props) => {
noWrap: true,
})
// ---- Layers on top of base maps ----
// Create a polygon layer for the country borders that is in layer control panel.
const borderLayer = L.layerGroup()
countryPolygons.forEach(countryBorder => {
L.polygon(countryBorder as LatLngExpression[], { color: 'gray', weight: 1 }).addTo(mapInstance)
const polygon = L.polygon(countryBorder as LatLngExpression[], {
color: '#136f94',
fillOpacity: 0.3,
weight: 1,
})
borderLayer.addLayer(polygon)
})
borderLayerRef.current = borderLayer
const baseMaps = {
OpenTopoMap: topomap,
OpenStreetMap: osm,
@@ -97,10 +105,26 @@ export const LocalitiesMap = ({ localities, isFetching }: Props) => {
northArrow.addTo(mapInstance)
return () => {
borderLayerRef.current = null
mapInstance.remove()
}
}, [])
useEffect(() => {
if (!map || !countryPolygons || !borderLayerRef.current) return
borderLayerRef.current.clearLayers()
countryPolygons.forEach(countryBorder => {
const polygon = L.polygon(countryBorder as LatLngExpression[], {
color: '#136f94',
fillOpacity: 0.3,
weight: 1,
})
borderLayerRef.current?.addLayer(polygon)
})
}, [countryPolygons, map])
useEffect(() => {
if (!map || isFetching) return