ESRIEACT
A react component library for the ArcGIS Javascript API.
Getting Started
Install / Get the Components
This project is very much a work in progress. The end goal would be to publish an npm package with these react components. In the meantime, simply copy the contents of the /lib folder into your codebase, and use the components directly.
Create a Map
import { MapView, FeatureLayer, LayerList } from '../lib';
const MyApp = () => {
return (
<MapView
style={{ width: '640px', height: '400px' }}
ViewProperties={{
extent: EXTENT_OBJECT,
events: {
click: e => console.log(e.mapPoint);
}
}}
>
<FeatureLayer url={FEATURELAYER_URL} />
<LayerList />
</MapView>
)
}
Use State
import { MapView, FeatureLayer, LayerList } from '../lib';
const MyApp = () => {
const [maxStorage, setMaxStorage] = useState(10000);
return (
<MapView>
<FeatureLayer url={FEATURELAYER_URL}>
<FeatureLayerView filter={{ where: `C_Storage < ${maxStorage}` }} />
</FeatureLayer>
</MapView>
)
}
Why ESRIEACT?
Pains of the Past
The goal of wrapping ArcGIS JS API components in react wrappers is to maintain a react-style flow of data, i.e. state and prop changes cause components to react and auto-update. For example, rendering a map, or map components, normally requires many useEffect
calls:
import React, { useEffect } from "react";
import Map from "@arcgis/core/Map";
import MapView from "@arcgis/core/views/MapView";
export const EffectBasedMap: React.FC = () => {
useEffect(() => {
const map = new Map({
basemap: "topo-vector",
});
new MapView({
container: "map-div",
map,
});
}, []);
return <div id="map-div" />;
};
While the above is not terribly complex or ugly, mangaging map state with React is more complex as we add more ESRI components. For example, keeping the map up to date with a list of layers requires some confusing useEffect
s:
export const EffectBasedMap: React.FC = ({ layerList }) => {
const [map, setMap] = useState<__esri.Map>();
useEffect(() => {
const map = new Map({
basemap: "topo-vector",
});
new MapView({
container: "map-div",
map,
});
setMap(map);
}, []);
useEffect(() => {
if (map) {
layerList.forEach((layer) => {
if (!map.layers.map((l) => l.id).includes(layer.id)) {
map.add(layer);
}
// We would also need some ugly logic here to test if the map has
// layers that are not part of the new layer list prop
});
}
}, [map, layerList]);
return <div id="map-div" />;
};
React + ArcGIS JS API = ESRIEACT
Instead, wrapper components are available to make map presentation clear and declarative:
import React from "react";
import { FeatureLayer, MapView } from "./esri";
export const ReactMap: React.FC = ({ layerList }) => {
return (
<MapView>
{layerList.map((layer) => (
<FeatureLayer url={layer.url} />
))}
</MapView>
);
};
The wrappers for ESRIEACT components often do not render anything, but rather simply use react lifecycle methods to manage the interaction of an ESRI component to the map. If children of a component are needed, ESRIEACT components render a context object that provides the ESRI instance to any children.
What about ESRI's react library?
ESRI recently released @arcgis/map-components-react, which offers some support for ArcGIS components in react. Their documentation shows a basic example, but in the current early stage of this library, react components for map layers, renderers, graphics, etc, do not exist, and must still be added to a map using the classic imperative programming style.