HERE Technologies предоставляет набор картографических сервисов, где ключевую роль в веб-разработке играет HERE Maps API for JavaScript. При интеграции с React основная сложность заключается не в инициализации карты, а в корректном управлении жизненным циклом компонентов, синхронизации DOM-узлов и предотвращении повторной инициализации SDK при каждом рендере.
React работает декларативно, тогда как HERE Maps API — императивный
SDK, напрямую взаимодействующий с DOM. Это приводит к необходимости
изоляции карты в пределах ref, контролируемого побочными
эффектами через useEffect, а также к строгому управлению
очисткой ресурсов.
Для работы с HERE Maps API в React чаще всего используется загрузка
скрипта через CDN или установка через npm-обёртки (если используются
сторонние пакеты). Базовый вариант предполагает подключение скриптов в
index.html:
<script src="https://js.api.here.com/v3/3.1/mapsjs-core.js"></script>
<script src="https://js.api.here.com/v3/3.1/mapsjs-service.js"></script>
<script src="https://js.api.here.com/v3/3.1/mapsjs-ui.js"></script>
<script src="https://js.api.here.com/v3/3.1/mapsjs-mapevents.js"></script>
<link rel="stylesheet" href="https://js.api.here.com/v3/3.1/mapsjs-ui.css" />
Ключевой момент — порядок загрузки модулей. core должен
быть загружен первым, затем сервисы, UI и события.
Альтернативный подход — динамическая загрузка скриптов внутри
React-приложения, что особенно важно при SSR-окружениях (например,
Next.js), где window недоступен на сервере.
Основной принцип интеграции — создание контейнера через
useRef и инициализация карты внутри useEffect,
чтобы гарантировать наличие DOM-узла.
import { useEffect, useRef } from "react";
const HERE_API_KEY = "YOUR_API_KEY";
export default function HereMap() {
const mapRef = useRef(null);
const mapInstance = useRef(null);
useEffect(() => {
if (!mapRef.current) return;
const platform = new window.H.service.Platform({
apikey: HERE_API_KEY,
});
const defaultLayers = platform.createDefaultLayers();
const map = new window.H.Map(
mapRef.current,
defaultLayers.vector.normal.map,
{
center: { lat: 48.8566, lng: 2.3522 },
zoom: 10,
pixelRatio: window.devicePixelRatio || 1,
}
);
const beh * avior = new window.H.mapevents.Behavior(
new window.H.mapevents.MapEvents(map)
);
const ui = window.H.ui.UI.createDefault(map, defaultLayers);
mapInstance.current = map;
return () => {
map.dispose();
};
}, []);
return <div ref={mapRef} style={{ width: "100%", height: "500px" }} />;
}
Ключевой аспект заключается в том, что экземпляр карты сохраняется отдельно от React-рендера. Это предотвращает повторное создание карты при каждом обновлении компонента.
HERE Maps API создаёт внутренние обработчики событий, WebGL-контекст и DOM-слои. При отсутствии корректного уничтожения экземпляра возникают утечки памяти.
Основной метод очистки:
return () => {
if (mapInstance.current) {
mapInstance.current.dispose();
mapInstance.current = null;
}
};
Особенно важно вызывать dispose() при:
Работа с объектами карты осуществляется через
H.map.Marker. В React добавление маркеров также выполняется
внутри useEffect, чтобы избежать повторного добавления.
useEffect(() => {
if (!mapInstance.current) return;
const marker = new window.H.map.Marker({
lat: 48.8566,
lng: 2.3522,
});
mapInstance.current.addObject(marker);
return () => {
mapInstance.current.removeObject(marker);
};
}, []);
Паттерн управления объектами карты должен повторять React-логику: добавление при монтировании, удаление при размонтировании.
Часто требуется синхронизировать состояние React с картой: координаты, масштаб, выбранные объекты.
useEffect(() => {
if (!mapInstance.current) return;
mapInstance.current.setCenter({
lat: props.lat,
lng: props.lng,
});
mapInstance.current.setZoom(props.zoom);
}, [props.lat, props.lng, props.zoom]);
Важно избегать обратной зависимости: изменения карты не должны бесконечно триггерить React state без дебаунса или фильтрации событий.
HERE Maps API предоставляет событийную модель через
mapevents. В React события должны регистрироваться и
сниматься корректно.
useEffect(() => {
if (!mapInstance.current) return;
const map = mapInstance.current;
const handleTap = (evt) => {
const coord = map.screenToGeo(
evt.currentPointer.viewportX,
evt.currentPointer.viewportY
);
console.log(coord);
};
map.addEventListener("tap", handleTap);
return () => {
map.removeEventListener("tap", handleTap);
};
}, []);
Особенность заключается в том, что события привязаны не к DOM, а к внутренней модели карты.
Для масштабируемых приложений целесообразно выделять логику карты в отдельные хуки.
import { useEffect, useRef } from "react";
export function useHereMap(center, zoom) {
const mapRef = useRef(null);
const instanceRef = useRef(null);
useEffect(() => {
if (!mapRef.current) return;
const platform = new window.H.service.Platform({
apikey: "YOUR_API_KEY",
});
const layers = platform.createDefaultLayers();
instanceRef.current = new window.H.Map(
mapRef.current,
layers.vector.normal.map,
{ center, zoom }
);
return () => {
instanceRef.current.dispose();
};
}, []);
useEffect(() => {
if (instanceRef.current) {
instanceRef.current.setCenter(center);
instanceRef.current.setZoom(zoom);
}
}, [center, zoom]);
return { mapRef, map: instanceRef.current };
}
Такой подход отделяет инфраструктуру карты от UI-логики компонента.
При использовании TypeScript основная проблема — отсутствие строгих
типов у глобального H объекта.
Можно определить минимальные типы:
declare global {
interface Window {
H: any;
}
}
Более строгий подход предполагает описание интерфейсов для карты, маркеров и событий, однако из-за сложности SDK часто используется частичная типизация.
При работе с большим количеством объектов на карте возникают проблемы производительности WebGL.
Основные техники оптимизации:
H.clusteringrequestAnimationFrame для анимацийsetCenter и
setZoomПример кластеризации:
const dataPoints = data.map(item => new window.H.clustering.DataPoint(
item.lat,
item.lng
));
const clusteringProvider = new window.H.clustering.Provider(dataPoints);
const layer = new window.H.map.layer.ObjectLayer(clusteringProvider);
mapInstance.current.addLayer(layer);
Поскольку HERE Maps API зависит от window, прямой импорт
приводит к ошибкам на сервере.
Решение — динамический импорт:
useEffect(() => {
if (typeof window === "undefined") return;
import("@here/maps-api-for-javascript").then(() => {
// инициализация карты
});
}, []);
Также допустимо полностью отключать SSR для компонента:
export default dynamic(() => import("./HereMap"), { ssr: false });
HERE Maps API позволяет переключать слои:
const layers = platform.createDefaultLayers();
map.setBaseLayer(layers.raster.satellite.map);
В React это часто связывается с состоянием UI:
useEffect(() => {
if (!mapInstance.current) return;
mapInstance.current.setBaseLayer(
layers[props.layerType]
);
}, [props.layerType]);
В интеграции React и HERE Maps API часто встречаются следующие проблемы:
dispose() и утечки памятиrefПравильная архитектура предполагает жёсткое разделение: React управляет UI-состоянием, HERE Maps — визуализацией и геометрией.
В крупных приложениях карта рассматривается как отдельный подсистемный слой:
Такое разделение позволяет изолировать взаимодействие с HERE Maps API for JavaScript от бизнес-логики React-приложения и уменьшает связность компонентов.