esri-loader-react

esri-loader-react is a small React component that wraps esri-loader.

esri-loader and esri-loader-react

If you’re doing web development with the Esri JS API then chances are that you’ve encountered issues with the dojo loader either using custom libraries, different JS frameworks or modern build tooling. esri-loader is a great way to circumvent these issues. It works by injecting the Esri JS API into your page at runtime so you only use the dojo loader for any Esri JS API modules that you need. It was originally written by @tomwayson and he has a great blog post on some of the challenges for this type of approach.

The API for esri-loader exposes 3 functions

  • isLoaded()
  • bootstrap(callback: Function, options = {} as any)
  • dojoRequire(modules: string[], callback: Function)

The typical workflow then becomes:

  • check if the Esri JS API is loaded using isLoaded
  • if not then bootstrap the API, this injects the script
  • if already loaded or when the script is ready then use dojoRequire to load Esri modules

Note that you still need to manage loading the CSS for the Esri JS API yourself, so adding it to the head section of your html is still required

esri-loader works with a variety of libraries and frameworks but if you are using React then you can use esri-loader-react. This is a component that essentially wraps some of the logic you would typically use with esri-loader so that you have less to do. The part it wraps is the initial call to isLoaded and bootstrap so that once it is ready then you can use dojoRequire as you would normally with esri-loader. It does this by using the React lifecycle event componentDidMount. So in your application you can mount esri-loader-react and think of it as the script tag for the Esri JS API. You only need to do this in one place in your application (the top most component for the application or route) and then you use dojoRequire from one or more other places in your application.

The API for esri-loader-react exposes 2 properties

  • options - this is passed through to the bootstrap function in esri-loader
  • ready - a function to be called when the component has mounted and the Esri JS API is ready

Usage

As well as previous advantages of using these libraries you can also benefit from pre or lazy loading the Esri JS API in your application rather than on initial page load. In its simplest usage you can do

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import React, { Component } from 'react';
import { dojoRequire } from 'esri-loader';
import EsriLoader from 'esri-loader-react';
class App extends Component {
createMap = () => {
dojoRequire(['esri/Map', 'esri/views/MapView'], (Map, MapView) => {
new MapView({
container: this.mapContainer,
map: new Map({ basemap: 'oceans' })
})
});
}
render() {
// you can omit options and it defaults to the latest version
const options = {
url: 'https://js.arcgis.com/4.4/'
};
return (
<div>
<EsriLoader options={options} ready={this.createMap} />
<div ref={node => this.mapContainer = node}></div>
</div>
);
}
}

comparing this to using esri-loader which would be

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import React, { Component } from 'react';
import * as esriLoader from 'esri-loader';
class App extends Component {
createMap = () => {
dojoRequire(['esri/Map', 'esri/views/MapView'], (Map, MapView) => {
new MapView({
container: this.mapContainer,
map: new Map({ basemap: 'oceans' })
})
});
}
componentDidMount() {
const options = {
url: 'https://js.arcgis.com/4.4/'
};
// has the ArcGIS API been added to the page?
if (!esriLoader.isLoaded()) {
// no, lazy load it the ArcGIS API before using its classes
esriLoader.bootstrap((err) => {
if (err) {
console.error(err);
} else {
// once it's loaded, create the map
this.createMap();
}
}, options);
} else {
// ArcGIS API is already loaded, just do something
this.createMap();
}
}
render() {
return (
<div>
<div ref={node => this.mapContainer = node}></div>
</div>
);
}
}

both work the same so feel free to use whichever you prefer. You could also convert it to a functional component.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import React from 'react';
import { dojoRequire } from 'esri-loader';
import EsriLoader from 'esri-loader-react';
const createMap = (mapContainer) => {
dojoRequire(['esri/Map', 'esri/views/MapView'], (Map, MapView) => {
new MapView({
container: mapContainer,
map: new Map({ basemap: 'oceans' })
})
});
}
function App ({options, ready}) {
let mapContainer = null;
return (
<div>
<EsriLoader options={options} ready={() => ready(mapContainer)} />
<div ref={node => mapContainer = node}></div>
</div>
);
}

which you could then call from somewhere in your app

1
2
3
4
5
6
7
8
9
10
import React from 'react';
import { render } from 'react-dom';
render(
<App
options={{url: 'https://js.arcgis.com/4.4/'}}
ready={createMap}
/>,
document.querySelector('#app')
);

Examples

Some examples that use esri-loader-react are

I haven’t used this but it looks to do something similar to esri-loader so check it out esri-promise