React + Leaflet образуют типичный стек для создания интерактивных веб-карт, где логика управления состоянием и компонентная модель React соединяется с императивным API Leaflet через слой абстракции React Leaflet. Эта библиотека реализует декларативную обёртку над объектами карты, слоями, маркерами и событиями Leaflet, позволяя управлять картой через React-компоненты вместо прямого вызова методов API.
Leaflet построен на императивной модели: карта и её элементы
создаются через вызовы вроде L.map(),
L.tileLayer() и L.marker(). React, напротив,
использует декларативную модель, где UI описывается как функция
состояния.
React-leaflet выступает мостом между этими подходами:
Ключевая идея: React-компонент не рисует карту напрямую, а создаёт и обновляет Leaflet-слой.
Основной контейнер — компонент MapContainer. Он
инициализирует экземпляр карты Leaflet и предоставляет контекст для
дочерних элементов.
import { MapContainer, TileLayer, Marker, Popup } from "react-leaflet";
export default function MapExample() {
return (
<MapContainer center={[55.751244, 37.618423]} zoom={10} style={{ height: "100vh" }}>
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<Marker position={[55.751244, 37.618423]}>
<Popup>
Центральная точка
</Popup>
</Marker>
</MapContainer>
);
}
Создаёт экземпляр карты Leaflet и связывает его с React-контекстом.
Основные параметры:
center — начальные координатыzoom — уровень масштабированияscrollWheelZoom — управление зумом колесом мышиwhenCreated — callback доступа к объекту картыLeaflet использует тайловую систему отображения карт. React-leaflet
инкапсулирует её через компонент TileLayer.
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution="© OpenStreetMap contributors"
/>
Особенности:
{z}/{x}/{y}Маркер представляет точечный объект на карте.
<Marker position={[51.505, -0.09]} />
Всплывающее окно привязывается к маркеру или любому слою.
<Marker position={[51.505, -0.09]}>
<Popup>
Лондон
</Popup>
</Marker>
Popup автоматически управляет привязкой к слою через контекст React-leaflet.
React-leaflet не хранит состояние карты в React напрямую, но предоставляет доступ к экземпляру Leaflet через хуки.
import { useMap } from "react-leaflet";
function ZoomController() {
const map = useMap();
function zoomIn() {
map.zoomIn();
}
return <button onCl ick={zoomIn}>Zoom In</button>;
}
Map — это прямой экземпляр Leaflet, позволяющий вызывать методы:
setViewflyTopanTofitBoundsLeaflet поддерживает богатую систему событий, которую React-leaflet оборачивает в props.
<Marker
position={[51.505, -0.09]}
eventHandlers={{
click: () => {
console.log("Marker clicked");
},
mouseover: () => {
console.log("Hover");
}
}}
/>
События проксируются напрямую из Leaflet-инстанса.
Изменение props автоматически приводит к обновлению слоя.
function MovingMarker({ position }) {
return <Marker position={position} />;
}
При изменении position React-leaflet вызывает
setLatLng внутри Leaflet.
import { Polyline } from "react-leaflet";
const path = [
[51.505, -0.09],
[51.51, -0.1],
[51.52, -0.12]
];
<Polyline positions={path} color="blue" />
import { Polygon } from "react-leaflet";
const triangle = [
[51.51, -0.12],
[51.5, -0.1],
[51.52, -0.09]
];
<Polygon positions={triangle} />
Эти компоненты напрямую соответствуют геометрическим слоям Leaflet.
Leaflet использует объект Icon, который можно
интегрировать через React-leaflet.
import L from "leaflet";
import { Marker } from "react-leaflet";
const icon = new L.Icon({
iconUrl: "/marker.png",
iconSize: [25, 41],
iconAnchor: [12, 41]
});
<Marker position={[51.505, -0.09]} icon={icon} />
import { useMap } from "react-leaflet";
function FitBounds({ bounds }) {
const map = useMap();
map.fitBounds(bounds);
return null;
}
Используется для автоматического масштабирования под набор координат.
import { LayerGroup, Marker } from "react-leaflet";
<LayerGroup>
<Marker position={[51.5, -0.09]} />
<Marker position={[51.51, -0.1]} />
</LayerGroup>
Позволяет управлять группой объектов как единым слоем.
Leaflet поддерживает GeoJSON напрямую.
import { GeoJSON } from "react-leaflet";
const data = {
type: "Feature",
geometry: {
type: "Point",
coordinates: [-0.09, 51.505]
}
};
<GeoJSON data={data} />
GeoJSON позволяет отображать сложные географические структуры: полигоны, линии, точки.
React-leaflet синхронизирует lifecycle React с lifecycle Leaflet:
mount → создание Leaflet-объектаupdate → вызов методов обновленияunmount → удаление слояЭто предотвращает утечки памяти при частых перерендерингах.
При работе с большим количеством объектов важны следующие аспекты:
useMemo для координатных массивовLayerGroupTileLayerПример оптимизации:
const positions = useMemo(() => generatePoints(), []);
Карты часто работают с API:
useEffect(() => {
fetch("/api/points")
.then(res => res.json())
.then(setPoints);
}, []);
React-leaflet использует Context API React для передачи экземпляра карты вниз по дереву компонентов.
Любой дочерний компонент внутри MapContainer получает
доступ к карте без явной передачи props.
Можно интегрировать кастомные DOM-элементы через
DivOverlay или собственные компоненты.
<Marker position={[51.505, -0.09]}>
<div className="custom-popup">
Кастомный контент
</div>
</Marker>
Несколько MapContainer могут существовать
независимо:
Это важно для dashboard-интерфейсов и аналитических панелей.
React Leaflet допускает интеграцию с плагинами Leaflet:
Подключение осуществляется через useEffect и доступ к
map:
const map = useMap();
useEffect(() => {
const control = L.control.scale();
control.addTo(map);
return () => control.remove();
}, [map]);