The packages google-maps-api-loader, google-maps-react, and react-google-maps all address the challenge of embedding Google Maps into React applications, but they solve different parts of the problem with varying levels of abstraction. google-maps-api-loader is a lightweight utility focused solely on asynchronously loading the Google Maps JavaScript API script into the browser environment without providing any React components. In contrast, google-maps-react and react-google-maps are higher-level libraries that wrap the Google Maps API to provide declarative React components (like <Map>, <Marker>, and <InfoWindow>), allowing developers to manage map state within the React lifecycle. However, a critical distinction exists in their maintenance status: both google-maps-react and react-google-maps are officially deprecated and no longer maintained, whereas google-maps-api-loader remains a viable, low-level tool for custom implementations or modern wrapper strategies.
When integrating Google Maps into a React application, developers often encounter a fragmented ecosystem of libraries. The packages google-maps-api-loader, google-maps-react, and react-google-maps represent three distinct approaches to this problem: low-level script loading, high-level declarative wrapping, and comprehensive component suites. However, the most critical factor in choosing between them today is not feature count, but maintenance status. Two of these libraries are officially deprecated, fundamentally changing how we should approach map integration in modern React architectures.
Before diving into code, it is essential to address the lifecycle status of these packages. Both google-maps-react and react-google-maps have been marked as deprecated by their maintainers. This means they no longer receive bug fixes, security patches, or updates to match changes in the Google Maps JavaScript API or React itself.
google-maps-react and react-google-maps were built during an era when React class components were the standard. They rely on lifecycle methods like componentDidMount and componentWillUnmount to manage map instances. As React has shifted toward hooks and functional components, these libraries have become architectural mismatches. Using them in new projects introduces significant technical debt and potential runtime errors.
google-maps-api-loader, on the other hand, remains active. It solves a single, timeless problem: loading the external Google Maps script asynchronously. Because it does not attempt to wrap the API into React components, it does not suffer from the same coupling issues as the deprecated libraries. It is a utility, not a framework, which gives it greater longevity.
Every Google Maps integration starts with loading the JavaScript library from Google's servers. This is where google-maps-api-loader shines, while the other two packages hide this process behind their internal logic.
google-maps-api-loader provides a clean, promise-based API to load the script. You explicitly call the loader, wait for the promise to resolve, and then access the global google object. This approach gives you full control over when and how the map initializes.
// google-maps-api-loader: Explicit script loading
import GoogleMapsApiLoader from 'google-maps-api-loader';
const initMap = async () => {
try {
await GoogleMapsApiLoader.load({
key: 'YOUR_API_KEY',
libraries: ['places', 'geometry']
});
// The global 'google' object is now available
const map = new google.maps.Map(document.getElementById('map'), {
center: { lat: 40.7128, lng: -74.0060 },
zoom: 12
});
} catch (error) {
console.error('Failed to load Google Maps', error);
}
};
google-maps-react and react-google-maps handle loading internally. You typically wrap your application or map component in a provider or configure it via props. While this reduces boilerplate, it obscures the loading state and makes error handling more difficult.
// google-maps-react: Internal loading via Wrapper
// (Deprecated pattern)
import { Map, GoogleApiWrapper } from 'google-maps-react';
class MapContainer extends React.Component {
render() {
return (
<Map
google={this.props.google}
zoom={11}
initialCenter={{ lat: 40.7128, lng: -74.0060 }}
/>
);
}
}
export default GoogleApiWrapper({
apiKey: 'YOUR_API_KEY'
})(MapContainer);
// react-google-maps: Internal loading via withScriptProps
// (Deprecated pattern)
import { withScriptProps, withGoogleMap, GoogleMap, Marker } from 'react-google-maps';
const MyMap = withScriptProps(withGoogleMap(props => (
<GoogleMap
defaultZoom={12}
defaultCenter={{ lat: 40.7128, lng: -74.0060 }}
>
<Marker position={{ lat: 40.7128, lng: -74.0060 }} />
</GoogleMap>
)));
The primary selling point of the deprecated libraries was their ability to treat map elements as React components. Instead of manually creating new google.maps.Marker(), you could write <Marker />. This declarative style felt natural in React but came with performance costs and rigidity.
google-maps-react allowed you to pass props directly to components like <Marker> or <InfoWindow>. However, syncing these props with the underlying Google Maps instance often led to performance issues, as the library had to reconcile React renders with the map's internal state.
// google-maps-react: Declarative Marker
// (Deprecated)
<Marker
name="Current Location"
position={{ lat: 40.7128, lng: -74.0060 }}
onClick={this.onMarkerClick}
/>
react-google-maps took this further with a complex architecture involving higher-order components (HOCs). While powerful, this made the code harder to read and debug. The separation between withScriptProps and withGoogleMap added layers of abstraction that confused many developers.
// react-google-maps: HOC-based Marker
// (Deprecated)
<Marker
position={{ lat: 40.7128, lng: -74.0060 }}
onClick={handleClick}
/>
google-maps-api-loader offers no components. You must write imperative code to create markers, info windows, and event listeners. While this requires more initial code, it results in better performance and clearer data flow. You interact directly with the Google Maps API, avoiding the "leaky abstraction" problems of the wrapper libraries.
// google-maps-api-loader: Imperative Marker Creation
// (Modern, supported approach)
const addMarker = (mapInstance) => {
const marker = new google.maps.Marker({
position: { lat: 40.7128, lng: -74.0060 },
map: mapInstance,
title: 'Current Location'
});
marker.addListener('click', () => {
console.log('Marker clicked');
});
return marker;
};
Managing state (like selected markers or map center changes) reveals the biggest gap between these tools.
In google-maps-react and react-google-maps, state management was often tied to the component lifecycle. Updating a prop would trigger a re-render, which the library would attempt to sync with the map. This often caused unnecessary map redraws or lost state if the synchronization logic failed.
// google-maps-react: Prop-driven state
// (Deprecated - prone to sync issues)
<Marker
position={this.state.currentLocation}
// Changing state triggers library reconciliation
/>
With google-maps-api-loader, you manage state using standard React hooks (useState, useEffect). You explicitly tell the map when to update. This separates React's rendering logic from the map's rendering logic, preventing conflicts.
// google-maps-api-loader: Hook-driven state
// (Modern pattern)
useEffect(() => {
if (mapInstance && currentLocation) {
mapInstance.setCenter(currentLocation);
// Explicitly update map without re-rendering entire component tree
}
}, [currentLocation, mapInstance]);
When you need advanced features like custom controls, complex overlays, or integration with third-party libraries, the limitations of the deprecated wrappers become obvious. They often lack APIs for niche features or require awkward workarounds to access the underlying google.maps object.
google-maps-react and react-google-maps expose the underlying map instance via props (e.g., this.props.map), but using it often broke the declarative model, leading to a mix of styles that was hard to maintain.
// google-maps-react: Mixing declarative and imperative
// (Deprecated)
componentDidMount() {
// Breaking the declarative flow to access raw API
this.props.map.fitBounds(bounds);
}
google-maps-api-loader gives you the raw API from day one. There is no barrier between you and the full power of Google Maps. If you need to draw a polygon, add a heatmap, or use the Places API, you simply call the official methods.
// google-maps-api-loader: Direct API access
const drawPolygon = (mapInstance) => {
const polygon = new google.maps.Polygon({
paths: coordinates,
strokeColor: '#FF0000',
fillColor: '#FF0000'
});
polygon.setMap(mapInstance);
};
| Feature | google-maps-api-loader | google-maps-react | react-google-maps |
|---|---|---|---|
| Status | β Active | β Deprecated | β Deprecated |
| Approach | Utility (Script Loading) | Wrapper (Components) | Wrapper (HOCs) |
| React Style | Functional / Hooks | Class Components | Class Components / HOCs |
| Control | Full Imperative Control | Limited Declarative | Complex Declarative |
| Learning Curve | Medium (Requires API knowledge) | Low (Initially) | High (Complex architecture) |
| Performance | High (Direct API) | Medium (Reconciliation overhead) | Medium (Reconciliation overhead) |
The choice here is clear when viewed through the lens of long-term maintenance. Do not start new projects with google-maps-react or react-google-maps. Their deprecated status means you are building on unstable ground. Any time saved today by using their declarative syntax will be lost tomorrow debugging incompatibilities or migrating away from them.
google-maps-api-loader is the only viable option among these three for modern development. It provides the essential service of loading the API reliably while leaving the architecture up to you. For the best developer experience, pair it with modern React patterns: create a custom hook to manage the map instance, use useRef to hold the map object, and use useEffect to handle updates. Alternatively, consider migrating to the officially recommended community wrapper, @react-google-maps/api, which offers the declarative convenience of the old libraries with active maintenance and hook support.
In summary, treat google-maps-api-loader as your foundation. It is the safe, flexible choice that respects the evolution of the React ecosystem.
Do NOT choose react-google-maps for new projects. Like google-maps-react, this library is deprecated and archived, offering no further development or bug fixes. It was once popular for its extensive component coverage, but its internal complexity and lack of maintenance make it unsuitable for modern development workflows. Developers should migrate to actively maintained alternatives or build custom solutions using the official Google Maps JavaScript API directly.
Do NOT choose google-maps-react for new projects. This package is deprecated and no longer maintained, meaning it lacks support for modern React features like hooks and may break with recent updates to the Google Maps API or React itself. While it previously offered a simple declarative syntax for maps, its architectural reliance on older React patterns makes it a liability for production applications requiring long-term stability and security updates.
Choose google-maps-api-loader if you need a reliable, dependency-free way to load the Google Maps script asynchronously before initializing your own map logic. It is the best choice for developers building custom hooks, using modern wrappers like @react-google-maps/api, or requiring full control over the google.maps namespace without the overhead of an abandoned component library. This package excels in scenarios where you want to avoid legacy class-component patterns and prefer functional React architectures.
React.js Google Maps integration component
The changelog is automatically generated via standard-version and can be found in project root as well as npm tarball.
Before doing this, did you:
You can get someone's help in three ways:
Please, be noted, no one, I mean, no one, is obligated to help you in ANY means. Your time is valuable, so does our contributors. Don't waste our time posting questions like βhow do I do X with React-Google-Mapsβ and βmy code doesn't workβ. This is not the primary purpose of the issue tracker. Don't abuse.
lib folder. They're generated during yarn release processsrc/macros -> src/components -> lib/componentsyarn and keep yarn.lock updated in PR