Уничтожение экземпляра карты

Экземпляр карты в Leaflet представляет собой объект класса L.Map, который управляет контейнером карты, слоями, обработчиками событий, элементами интерфейса и внутренними механизмами библиотеки. После создания карта остаётся активной до тех пор, пока существует соответствующий объект и связанные с ним ресурсы.

В долгоживущих веб-приложениях карта может многократно создаваться и удаляться. Особенно часто это происходит в:

  • одностраничных приложениях (SPA);
  • модальных окнах;
  • динамически подгружаемых компонентах;
  • интерфейсах с переключением между страницами без полной перезагрузки;
  • приложениях на React, Vue, Angular и других фреймворках.

Для корректного освобождения ресурсов Leaflet предоставляет специальный метод:

map.remove();

Данный метод полностью уничтожает карту и отключает связанные с ней механизмы.


Метод remove()

Сигнатура метода:

map.remove();

Пример:

const map = L.map('map').setView([55.751244, 37.618423], 10);

// Работа с картой

map.remove();

После вызова метода:

  • удаляются обработчики событий;
  • отключаются механизмы масштабирования и перемещения;
  • удаляются внутренние ссылки на контейнер;
  • уничтожаются слои карты;
  • освобождаются внутренние структуры данных Leaflet.

Что происходит при вызове remove()

Рассмотрим внутренние процессы более подробно.

Удаление обработчиков событий

Во время работы карта регистрирует множество событий:

map.on('click', handler);
map.on('zoomend', zoomHandler);
map.on('moveend', moveHandler);

После выполнения:

map.remove();

все зарегистрированные обработчики автоматически отключаются.

Дополнительный вызов:

map.off();

обычно не требуется.


Остановка интерактивных механизмов

Leaflet создаёт множество компонентов взаимодействия:

  • Dragging;
  • Scroll Wheel Zoom;
  • Box Zoom;
  • Touch Zoom;
  • Double Click Zoom;
  • Keyboard Navigation.

Например:

map.dragging.enable();
map.scrollWheelZoom.enable();

После удаления карты все эти механизмы отключаются автоматически.


Удаление слоёв

Карта может содержать большое количество слоёв:

L.tileLayer(url).addTo(map);

L.marker([55.75, 37.61]).addTo(map);

L.circle([55.76, 37.62]).addTo(map);

При уничтожении карты Leaflet удаляет все зарегистрированные слои.

Пример:

const marker = L.marker([55.75, 37.61]).addTo(map);

map.remove();

Маркер перестаёт существовать в контексте карты.


Очистка контейнера

Пусть карта была создана в элементе:

<div id="map"></div>

После вызова:

map.remove();

Leaflet очищает контейнер от собственных элементов:

<div id="map"></div>

Внутренние панели, тайловые контейнеры, SVG-элементы и служебные узлы удаляются.


Повторное создание карты

Одна из самых распространённых причин использования remove() — повторная инициализация карты.

Неправильный подход

const map = L.map('map');

const map2 = L.map('map');

Результат:

Map container is already initialized.

Leaflet обнаруживает, что контейнер уже связан с существующей картой.


Правильный подход

let map = L.map('map');

map.remove();

map = L.map('map');

Теперь контейнер освобождён и может использоваться повторно.


Удаление карты перед сменой страницы

В SPA-приложениях компоненты могут уничтожаться без обновления страницы.

Пример логики:

function destroyPage() {
    map.remove();
}

При переходе на другую страницу:

destroyPage();

карта полностью освобождает ресурсы.

Без этого постепенно накапливаются:

  • слушатели событий;
  • DOM-элементы;
  • ссылки на объекты;
  • потребляемая память.

Уничтожение карты в React

В React карта обычно создаётся внутри useEffect.

Пример:

useEffect(() => {
    const map = L.map('map').setView([55.75, 37.61], 10);

    return () => {
        map.remove();
    };
}, []);

Функция очистки выполняется:

  • при размонтировании компонента;
  • перед повторным выполнением эффекта.

Это предотвращает утечки памяти.


Уничтожение карты в Vue

Пример для Vue:

import { onMounted, onUnmounted } from 'vue';

let map;

onMounted(() => {
    map = L.map('map');
});

onUnmounted(() => {
    map.remove();
});

После удаления компонента карта корректно уничтожается.


Уничтожение карты в Angular

Пример:

ngOnDestroy() {
    this.map.remove();
}

Метод жизненного цикла ngOnDestroy() является естественным местом для освобождения ресурсов.


Проверка существования карты перед удалением

Иногда карта может ещё не быть создана.

Небезопасный вариант:

map.remove();

Если map равно null, возникнет ошибка.

Безопасный вариант:

if (map) {
    map.remove();
}

Или:

map?.remove();

Повторный вызов remove()

После уничтожения карты повторный вызов обычно не имеет смысла.

Плохая практика:

map.remove();
map.remove();

Лучше сразу обнулить ссылку:

map.remove();
map = null;

Так становится очевидно, что объект больше не используется.


Очистка ссылок после удаления

Даже после уничтожения карты переменная может продолжать хранить ссылку на объект.

Пример:

let map = L.map('map');

map.remove();

Объект уничтожен, но ссылка сохраняется.

Рекомендуемый вариант:

map.remove();
map = null;

Это помогает сборщику мусора быстрее освободить память.


Удаление карты и пользовательские обработчики

Leaflet удаляет собственные обработчики карты, однако дополнительные подписки на сторонние объекты могут требовать ручной очистки.

Пример:

window.addEventListener('resize', updateMap);

Даже после:

map.remove();

обработчик окна останется активным.

Необходимо явно удалить его:

window.removeEventListener('resize', updateMap);

Удаление карты с большим количеством объектов

Предположим, карта содержит тысячи элементов:

for (let i = 0; i < 10000; i++) {
    L.marker([
        55 + Math.random(),
        37 + Math.random()
    ]).addTo(map);
}

Вызов:

map.remove();

удалит все зарегистрированные слои автоматически.

Нет необходимости выполнять:

map.eachLayer(layer => {
    map.removeLayer(layer);
});

непосредственно перед уничтожением всей карты.


Разница между removeLayer() и remove()

removeLayer()

Удаляет конкретный слой.

map.removeLayer(marker);

После выполнения:

  • карта продолжает существовать;
  • остальные слои остаются на месте.

remove()

Удаляет всю карту.

map.remove();

После выполнения:

  • исчезают все слои;
  • удаляются элементы интерфейса;
  • отключаются события;
  • освобождается контейнер.

Разница между clearLayers() и remove()

Очистка группы слоёв

markers.clearLayers();

Удаляются только объекты внутри группы.

Карта продолжает работать.


Уничтожение карты

map.remove();

Удаляется вся инфраструктура карты.


Типичный жизненный цикл карты

Создание:

const map = L.map('map');

Добавление слоёв:

tileLayer.addTo(map);
marker.addTo(map);

Регистрация событий:

map.on('click', onClick);

Работа приложения:

map.setZoom(12);

Удаление:

map.remove();
map = null;

Такой сценарий считается наиболее правильным и безопасным при управлении жизненным циклом экземпляра карты Leaflet.


Практические рекомендации

Всегда вызывать remove() перед удалением контейнера карты из DOM.

map.remove();
container.remove();

Освобождать ссылку после уничтожения.

map.remove();
map = null;

Использовать очистку в хуках жизненного цикла компонентов.

return () => map.remove();

Не создавать новую карту в уже инициализированном контейнере.

map.remove();
map = L.map('map');

Удалять сторонние обработчики событий отдельно, если они были созданы вручную.

window.removeEventListener('resize', handler);

Грамотное использование remove() позволяет избежать утечек памяти, повторной инициализации контейнеров, накопления обработчиков событий и деградации производительности в крупных приложениях, активно использующих Leaflet.