perf(map): reuse resources across routes
Build Push and Deploy / docker-image (push) Successful in 54s
Build Push and Deploy / deploy-fallback-log (push) Has been skipped

Preserve standard network layers between map pages while disposing route-owned overlays and controls to prevent memory growth.
This commit is contained in:
2026-07-10 15:31:14 +08:00
parent c6e6e24aab
commit f5e7312e3b
36 changed files with 753 additions and 703 deletions
@@ -14,8 +14,21 @@ import mapboxStreets from "@assets/map/layers/mapbox-streets.png";
import clsx from "clsx";
import { MAPBOX_TOKEN, TIANDITU_TOKEN } from "@config/config";
import type { Map as OlMap } from "ol";
import { markMapResourcePersistent } from "../mapLifecycle";
const INITIAL_LAYER = "mapbox-light";
const BASE_LAYER_METADATA = [
{ id: "mapbox-light", name: "默认地图", img: mapboxLight.src },
{ id: "mapbox-satellite", name: "卫星地图", img: mapboxSatellite.src },
{
id: "mapbox-satellite-streets",
name: "卫星街道地图",
img: mapboxSatelliteStreet.src,
},
{ id: "mapbox-streets", name: "街道地图", img: mapboxStreets.src },
{ id: "tianditu-vector", name: "天地图矢量", img: mapboxOutdoors.src },
{ id: "tianditu-image", name: "天地图影像", img: mapboxSatellite.src },
] as const;
const createTileLayer = (url: string, attributions: string) =>
new TileLayer({
@@ -77,46 +90,37 @@ const createBaseLayerEntries = () => {
return [
{
id: "mapbox-light",
name: "默认地图",
...BASE_LAYER_METADATA[0],
layer: lightMapLayer,
img: mapboxLight.src,
},
{
id: "mapbox-satellite",
name: "卫星地图",
...BASE_LAYER_METADATA[1],
layer: satelliteLayer,
img: mapboxSatellite.src,
},
{
id: "mapbox-satellite-streets",
name: "卫星街道地图",
...BASE_LAYER_METADATA[2],
layer: satelliteStreetsLayer,
img: mapboxSatelliteStreet.src,
},
{
id: "mapbox-streets",
name: "街道地图",
...BASE_LAYER_METADATA[3],
layer: streetsLayer,
img: mapboxStreets.src,
},
{
id: "tianditu-vector",
name: "天地图矢量",
...BASE_LAYER_METADATA[4],
layer: new Group({
layers: [tiandituVectorLayer, tiandituVectorAnnotationLayer],
}),
img: mapboxOutdoors.src,
},
{
id: "tianditu-image",
name: "天地图影像",
...BASE_LAYER_METADATA[5],
layer: new Group({
layers: [tiandituImageLayer, tiandituImageAnnotationLayer],
}),
img: mapboxSatellite.src,
},
];
].map((entry) => ({
...entry,
layer: markMapResourcePersistent(entry.layer),
}));
};
const BaseLayers: React.FC = () => {
@@ -158,11 +162,7 @@ const BaseLayers: React.FC = () => {
});
};
const baseLayers = useMemo(() => createBaseLayerEntries().map(({ id, name, img }) => ({
id,
name,
img,
})), []);
const baseLayers = BASE_LAYER_METADATA;
const handleQuickSwitch = () => {
const nextId =
@@ -194,6 +194,15 @@ const BaseLayers: React.FC = () => {
}, 300);
};
useEffect(
() => () => {
if (hideTimer.current) {
clearTimeout(hideTimer.current);
}
},
[],
);
return (
<div className="absolute right-17 bottom-11 z-20">
<div
@@ -1,6 +1,7 @@
import React, { useEffect, useState, useRef } from "react";
import { useMap } from "../MapComponent";
import { ScaleLine } from "ol/control";
import { markMapResourcePersistent } from "../mapLifecycle";
const Scale: React.FC = () => {
const map = useMap();
@@ -31,14 +32,16 @@ const Scale: React.FC = () => {
updateZoomLevel();
// ScaleLine control
const scaleControl = new ScaleLine({
target: scaleLineRef.current || undefined,
units: "metric",
bar: false,
steps: 4,
text: true,
minWidth: 64,
});
const scaleControl = markMapResourcePersistent(
new ScaleLine({
target: scaleLineRef.current || undefined,
units: "metric",
bar: false,
steps: 4,
text: true,
minWidth: 64,
}),
);
map.addControl(scaleControl);
return () => {