Библиотека Deck.gl изначально проектировалась как компонентная система визуализации данных, хорошо сочетающаяся с архитектурой React. Основная идея заключается в том, что React управляет состоянием приложения и жизненным циклом компонентов, а Deck.gl отвечает за высокопроизводительный рендеринг слоёв на базе WebGL.
В React-приложении Deck.gl обычно используется через компонент
DeckGL, который получает набор слоёв и параметры
отображения через свойства (props).
Типичная схема взаимодействия выглядит следующим образом:
React State
↓
React Components
↓
DeckGL Component
↓
Layers
↓
WebGL Rendering
Такой подход позволяет использовать декларативную модель React при работе с большими объёмами геоданных.
Для интеграции необходимы основные пакеты Deck.gl:
npm install deck.gl
Чаще всего дополнительно используются картографические библиотеки:
npm install react-map-gl maplibre-gl
или
npm install react-map-gl mapbox-gl
Современные проекты всё чаще используют MapLibre как полностью открытое решение без привязки к коммерческим лицензиям.
Минимальная интеграция в React выглядит следующим образом:
import DeckGL from '@deck.gl/react';
import {ScatterplotLayer} from '@deck.gl/layers';
function App() {
const layer = new ScatterplotLayer({
id: 'points',
data: [
{
position: [37.6176, 55.7558]
}
],
getPosition: d => d.position,
getRadius: 1000,
getFillColor: [255, 0, 0]
});
return (
<DeckGL
initialViewState={{
longitude: 37.6176,
latitude: 55.7558,
zoom: 10
}}
controller={true}
layers={[layer]}
/>
);
}
export default App;
Здесь происходит:
layers.На практике слои редко создаются непосредственно внутри JSX. Обычно используется разделение логики.
Пример:
import {useMemo} from 'react';
import DeckGL from '@deck.gl/react';
import {ScatterplotLayer} from '@deck.gl/layers';
function MapView({data}) {
const layers = useMemo(() => [
new ScatterplotLayer({
id: 'cities',
data,
getPosition: d => d.coordinates,
getRadius: 5000
})
], [data]);
return (
<DeckGL
controller
layers={layers}
initialViewState={{
longitude: 30,
latitude: 50,
zoom: 4
}}
/>
);
}
Использование useMemo предотвращает пересоздание слоя
при каждом рендере компонента.
Это особенно важно при работе с сотнями тысяч объектов.
React позволяет полностью контролировать состояние камеры через
useState.
import {useState} from 'react';
const INITIAL_VIEW_STATE = {
longitude: 37.6176,
latitude: 55.7558,
zoom: 10,
pitch: 0,
bearing: 0
};
function App() {
const [viewState, setViewState] =
useState(INITIAL_VIEW_STATE);
return (
<DeckGL
viewState={viewState}
controller
onViewStateCha nge={({viewState}) =>
setViewState(viewState)
}
/>
);
}
Преимущества такого подхода:
Deck.gl хорошо работает с современными возможностями React.
Хранение данных:
const [points, setPoints] = useState([]);
Создание слоя:
const layers = [
new ScatterplotLayer({
id: 'points',
data: points
})
];
После обновления массива автоматически запускается новый рендер.
Загрузка данных с сервера:
useEffect(() => {
fetch('/api/points')
.then(response => response.json())
.then(data => setPoints(data));
}, []);
После получения данных слой обновится автоматически.
Для тяжёлых вычислений:
const processedData = useMemo(() => {
return rawData.map(item => ({
...item,
value: item.sales * item.rate
}));
}, [rawData]);
Для обработчиков событий:
const handleClick = useCallback(info => {
console.log(info.object);
}, []);
Использование useCallback уменьшает количество лишних
пересозданий функций.
Одним из наиболее распространённых сценариев является наложение слоёв Deck.gl поверх интерактивной карты.
import DeckGL from '@deck.gl/react';
import Map from 'react-map-gl/maplibre';
function App() {
return (
<DeckGL
controller
layers={layers}
initialViewState={{
longitude: 37.6176,
latitude: 55.7558,
zoom: 10
}}
>
<Map
mapStyle="https://demotiles.maplibre.org/style.json"
/>
</DeckGL>
);
}
В этом случае:
React позволяет удобно собирать массив слоёв.
const layers = [
roadsLayer,
buildingsLayer,
labelsLayer,
heatmapLayer
];
Либо:
const layers = useMemo(() => {
return [
createRoadLayer(),
createBuildingLayer(),
createHeatmapLayer()
];
}, [data]);
Подобный подход облегчает поддержку крупных проектов.
Поскольку слой является обычным объектом JavaScript, можно использовать стандартные механизмы React.
const layers = [
showCities && cityLayer,
showRoads && roadLayer,
showHeatmap && heatmapLayer
].filter(Boolean);
Управление отображением производится через состояние:
const [showHeatmap, setShowHeatmap] =
useState(true);
Deck.gl поддерживает множество событий взаимодействия.
const layer = new ScatterplotLayer({
id: 'points',
data,
pickable: true,
onClick: info => {
console.log(info.object);
}
});
const layer = new ScatterplotLayer({
id: 'points',
data,
pickable: true,
onHover: info => {
console.log(info.x, info.y);
}
});
const layer = new ScatterplotLayer({
id: 'points',
data,
onDragStart: info => {},
onDrag: info => {},
onDragEnd: info => {}
});
Типичный React-подход заключается в хранении выбранного объекта в состоянии.
const [selected, setSelected] =
useState(null);
При клике:
onClick: info => {
setSelected(info.object);
}
Отображение:
{
selected && (
<div className="popup">
{selected.name}
</div>
)
}
Deck.gl отвечает за выбор объекта, а React — за пользовательский интерфейс.
Загрузка может выполняться из различных источников.
Пример с REST API:
useEffect(() => {
async function loadData() {
const response =
await fetch('/api/geojson');
const json =
await response.json();
setData(json.features);
}
loadData();
}, []);
После обновления состояния слой автоматически перестроится.
GeoJSON является наиболее распространённым форматом пространственных данных.
import {GeoJsonLayer}
from '@deck.gl/layers';
const geoLayer = new GeoJsonLayer({
id: 'geojson',
data: geojsonData,
filled: true,
stroked: true,
getFillColor: [50, 120, 255, 100]
});
В React компоненте:
const layers = useMemo(
() => [geoLayer],
[geojsonData]
);
При большом количестве компонентов данные карты удобно хранить через Context.
import {createContext} from 'react';
export const MapContext =
createContext(null);
Провайдер:
<MapContext.Provider
value={{
viewState,
setViewState
}}
>
{children}
</MapContext.Provider>
Получение данных:
const {
viewState,
setViewState
} = useContext(MapContext);
Это позволяет синхронизировать состояние между панелями, фильтрами и картой.
В крупных приложениях состояние карты часто хранится централизованно.
const viewState =
useSelector(state => state.map);
const dispatch = useDispatch();
Обновление камеры:
onViewStateCha nge={({viewState}) =>
dispatch(updateViewState(viewState))
}
Преимущества:
Наиболее важная оптимизация:
const layers = useMemo(
() => [
new ScatterplotLayer({...})
],
[data]
);
Без неё каждый рендер React создаёт новый экземпляр слоя.
const onCl ick =
useCallback(info => {
setSelected(info.object);
}, []);
Нежелательно хранить в состоянии огромные массивы, если данные не меняются.
Плохой вариант:
setData([...data]);
при каждом взаимодействии пользователя.
Лучше обновлять только действительно изменившиеся данные.
Вместо:
<App />
с тысячами строк логики предпочтительнее:
<Map />
<Sidebar />
<Filters />
<Toolbar />
Изолированные компоненты вызывают меньше лишних рендеров.
Deck.gl использует WebGL и не может выполняться на сервере в полном объёме.
Для проектов на Next.js обычно применяется динамический импорт.
import dynamic from 'next/dynamic';
const Map = dynamic(
() => import('./Map'),
{
ssr: false
}
);
Так компонент будет загружен только в браузере.
Пример структуры крупного React-приложения:
src/
│
├── components/
│ ├── Map/
│ │ ├── MapView.jsx
│ │ ├── Layers.jsx
│ │ └── Controls.jsx
│ │
│ ├── Sidebar/
│ └── Charts/
│
├── hooks/
│ ├── useMapData.js
│ ├── useViewport.js
│
├── store/
│
├── services/
│
└── pages/
Такое разделение упрощает масштабирование приложения и поддержку большого количества визуализаций.
Часто логика работы с картой выносится в отдельный хук.
function useCities() {
const [cities, setCities] =
useState([]);
useEffect(() => {
fetch('/api/cities')
.then(r => r.json())
.then(setCities);
}, []);
return cities;
}
Использование:
const cities = useCities();
Затем данные передаются непосредственно в слой.
В большинстве React-приложений с Deck.gl используется следующий цикл:
API
↓
React State
↓
Hooks
↓
Layers
↓
DeckGL
↓
WebGL
↓
Пользовательское взаимодействие
↓
Обновление State
↓
Повторный рендер
Такая архитектура сочетает декларативную модель React с высокопроизводительным GPU-рендерингом Deck.gl, позволяя строить масштабируемые картографические системы, аналитические панели, геоинформационные сервисы и приложения визуализации больших пространственных данных.