Using Global Military Bases to Spread the Holiday Spirit

Mapping Foreign Bases Using React-Leaflet in Conjunction with React-Redux

Josh Gumerove
12 min readDec 3, 2021

React is a front-end framework that has gained increasing popularity over the last few years. Originally created by Meta(formerly Facebook) — React provides a specific way to organize and structure the design of a web-application. React utilizes JSX — which allows users to write code that looks very similar to HTML:

React code

Although React code may seem significantly different from vanilla JavaScript — React is in fact an extension of JavaScript. Snippets of JSX get separated into React components, which let users split the User Interface(UI) into independent, reusable pieces — allowing developers to think about each piece of the UI in isolation. For more information regarding JSX and React Components please see the tutorial below:

Why Use Redux with React

React alone provides a way for programmers to structure code in a well-organized, modular fashion. However, React makes extensive use of props and state — which can quickly make the development process esoteric (and more error prone) without a centralized place to manage application state. Note — although there are differences between state and props — state is similar to props. Mainly, state is private and fully controlled by the creator component. However, state may be passed down from a parent component to a child component as props. Redux provides a centralized location for the management of application state — allowing us to more easily predict changes that will occur in our applications.

Building a React Redux Application

With the aforementioned in mind, I will now provide details about the development of my most recent application MilitaryMistletoe — a Christmas-themed interactive map application which allows users to view the foreign military bases different countries have around the world. Video demonstration below:

Step-1: Creating and Setting-Up the Application

It is important to note that Ruby on Rails was used as an API for the backend of MilitaryMistletoe. This article will not discuss the Rails portion of this application. In order to create a single-page application first run the following command in your terminal:

This will create the bare-bones structure of your React application which will include the following:

  1. A CSS file for styling.
  2. An index.html file which will (partially) be rendered by Index.js.
  3. An App.js file (the main component acting as a container for all other components) which will also be rendered by Index.js.
  4. The Index.js file responsible for injecting the main (App.js) component into the “root” element of the index.html file — which is then rendered to the DOM.

After creation, dependencies must be installed and imported into the necessary files in order to give the application its desired functionality:

index.js

Note the standard imports — as well as the the imports related to React-Router and React-Redux. Detailed configuration of React-Redux will be given in the following sections. React-Router allows for client-side routing — giving the front-end of an application the ability to handle the routing, fetching and displaying of data in the browser — responsibilities traditionally handled by the server-side of an application. This allows for navigation amongst views (within a single page application) of various components in a React application — while simultaneously changing the browser URL. For further information on React-Router please consult the following resource:

Step-2: Setting-Up Redux

The Redux store is a state container which holds the entire application state. In order to update state — the store must dispatch an action — which will then pass through a reducer. Since the store will serve as the foundation from which the application state is updated, our configuration will begin with its arrangement. In the proceeding section, we imported the following into our index.js file:

index.js

With the following at our disposal — it is time to make use of these imports to create our store:

index.js

The createStore function accepts a maximum of three arguments. However — the only parameter required by createStore is a reducer. In the code above, we passed the reducer(subjectively named countriesReducer) to the Redux createStore function — which returns a store object. Aside from the reducer — createStore may accept an initial value of state as well as an enhancer as (additional) optional arguments. Enhancers extend the functionality of the Redux store by allowing for the addition of middleware. Since thunk and the Redux Devtools Extension are middleware— the code above is used to allow the store to use both within the application.

Once the store is created — we must give the store a way to interact with the React application. This is done through the Provider component — imported from the react-redux library:

index.js

The Provider component makes the Redux store available to any nested components that need access to the Redux store. By wrapping our root App component with the Provider component (i.e. nesting) — and passing the store (previously created) as a property to the Provider component — our entire application is connected to the store:

index.js

Step-3: Creating the Reducer

The store will ultimately interact with a reducer in order to change application state. Although we already passed a reducer to the createStore function — this was done for brevity. Usually, the reducer would be created and then — only after — passed as an argument to createStore:

countriesReducer.js

The reducer function accepts two arguments — the (application) state and an action. When the reducer is initially executed — the application state has not yet been defined — therefore an initial state must be provided to the reducer. The reducer determines how to change (previous) state through actions. An action is a plain object with a type key and an (optional) payload. Since the reducer is just a function with a switch/case statement — the reducer will return a new state based on the action type provided (as an argument).

Step-4: Defining Action Creators

An action is simply a plain JavaScript object that has a type property. When an action is dispatched — the reducer uses its type property to determine how to update application state. The store has a (built-in Redux) dispatch method — which can be used to send an action to the reducer. However, we can also define functions with the sole purpose of returning an action. This allows for abstractions— we can create functions called action creators — which have equivalent action types and different action payload data.

However, action creators are still subject to limitations. These functions on their own are incapable of fetching data — and therefore middleware must be used in order to make asynchronous web requests within our action creators. By utilizing Redux Thunk — we are able to slightly alter the behavior of our actions — allowing for asynchronous requests:

fetchCountries.js

As seen above, the action creators within our application now have the ability to make API requests to a back-end server. A link to this project GitHub repository is provided at the end — further examples may be found within the repository.

Incorporating React-Leaflet Within the Application

React-Leaflet provides components the ability to render interactive maps within an application. An extension of Leaflet.js, React-Leaflet is poorly documented — making initial configuration difficult. To start the installation process, the following terminal commands must be run:

  1. npm install leaflet

2. npm install react react-dom leaflet

3. npm install react-leaflet

After running the above, import the following into App.js:

App.js

In order to create components containing leaflet maps, the following components must be imported from react-leaflet inside the file within which the map will be included:

WorldMapContainer.js

Please see the following for a brief overview on creating react-leaflet maps:

If the above instructions still produce unsuccessful results, delete the following from the package.json file (if present):

Once configuration is completed — follow the process outlined below to create and incorporate leaflet maps within an application.

Creating a Leaflet Map with React-Redux

WorldMapContainer.js

The code snippet above renders a map containing multiple markers — each representing a country possessing foreign military bases. I am well aware of the advent of hooks within functional components. However — I decided to use class components with component lifecycle methods. Notice (as previously mentioned) how we previously imported the following from React-Leaflet:

WorldMapContainer.js

These are React-Leaflet components that must be used in order to create a leaflet map. Below is an explanation of each.

The MapContainer

The MapContainer component is responsible for creating a Leaflet Map instance — and also providing the map to the container’s child components using React Context. This component requires a center position property (props) — which is an array containing latitude and longitude — along with a default zoom level for the map. The higher the zoom level — the greater the focus will be on the (original) center position. A zoom level of 0 would provide the least amount of focus — displaying the entire map and virtually making our center position irrelevant. At the other extreme, a zoom level of 18 would provide maximum focus — allowing one to see restaurants, shops and other attractions within the area of the center position.

TileLayer

The TileLayer component (nested inside MapContainer) gives attribution to OpenStreetMap — the intellectual property holders of the map used within our application. Without providing attribution, credit (displayed on the bottom right of the map) would not properly be attributed — potentially giving rise to legal issues. In addition, a URL is provided within the component — which provides the literal map rendered by the browser. This map can be altered and styled through the use of props; in React Leaflet — child components use their own props as options when creating a corresponding Leaflet instance. In the code above, the noWrap property is set to true — preventing continent repetition — which would otherwise occur when the map becomes less focused.

The Marker and Popup Components

The Marker component is used to display clickable/draggable icons on the map. Although React-Leaflet displays a default icon — this icon may be customized and changed. Notice the difference between the icon used within our application (on the left) — and the default icon (on the right):

Customizing an icon first requires the creation of a new icon instance — and therefore the following must be imported:

WorldMapContainer.js

Additionally — the image used in lieu of the leaflet provided default-icon must be imported into the application. After creating a file containing the desired image — import this image into the file containing the leaflet map:

WorldMapContainer.js

A leaflet icon is an object represented by default key-value pairs. In order to change these values, a new icon which overrides these default values must be returned. Therefore — we can create a function which returns a new icon instance containing the customized values we desire:

WorldMapContainer.js

The iconUrl property above now has a value equal to the image previously imported into our file (the image we would like to use as our icon). With this new icon in hand — the marker icon can be changed by passing the Marker component an icon property and calling the function above to set the (new) icon properties:

Note— this must be used prior to the function call since we are within a class component.

Without a position property specifying latitude and longitude coordinates — a marker will not be rendered. However — rather than hard-code these values for each country — the application makes use of Redux — storing these values within application state:

WorldMapContainer.js

Using React-Redux — we can connect our component to the Redux store — and provide our component access to the necessary fragments of the application state:

WorldMapContainer.js

Through mapStateToProps — our MapContainer is provided access to the countries portion of the application state (as props) — an array of objects which we can then map through in order to place multiple markers on our map. However — as mentioned previously — the reducer function must be provided with an initial state. This initial state sets the countries portion of our application to an empty array:

countriesReducer.js

Upon initial render — the actual map displayed to the browser does not contain any marker icons. However, within our components — we are able to dispatch actions (mapDispatchToProps)— causing the data within application state to change. Therefore, we are able to dispatch actions within the componentDidMount component lifecycle method — and load additional data after the initial render:

WorldMapContainer.js

Calling the fetchCountries action creator will fetch data from our backend (Rails) API — and update the countries portion of our application state (after passing through the reducer):

fetchCountries.js

Since dispatching the above action within the componentDidMount lifecycle method changes state — the component will re-render — and the updated data of the countries array (the updated state of countries) will be displayed.

Since countries contains an array of objects — the attributes of these objects must be considered when mapping through the array. We can destructure these attributes as seen below:

WorldMapContainer.js

Using the destructured properties for long and lat — positions for each country within the countries array may be created — displaying multiple markers on the map.

Nested within each Marker is a Popup component. These components display popup information each time a marker icon is clicked. Using the destructured properties (previously discussed) — we can provide each Popup with a country name. This name will be displayed each time a particular marker (nutcracker icon) is pressed. Since the application makes use of react-router — each name within our application also serves as a link — directing users to a particular country page.

Please feel free to download this application (GitHub repository provided below). If you enjoyed this article — please consider giving a clap. Please direct any questions to the comment section and I will attempt to provide an answer as soon as possible. Happy Holidays!

--

--