React.js Google Maps API integration with components and hooks for seamless Google Maps functionality
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
The main GoogleMap component that renders the interactive map container and manages the Google Maps instance, along with the useGoogleMap hook for accessing the map instance from child components.
The primary component for rendering Google Maps with comprehensive configuration options and event handling.
/**
* Main map container component that renders the Google Map
* All other map components must be rendered as children of GoogleMap
*/
interface GoogleMapProps {
children?: React.ReactNode;
id?: string;
mapContainerStyle?: React.CSSProperties;
mapContainerClassName?: string;
options?: google.maps.MapOptions;
extraMapTypes?: google.maps.MapType[];
// Map configuration
center?: google.maps.LatLng | google.maps.LatLngLiteral;
clickableIcons?: boolean;
heading?: number;
mapTypeId?: string;
streetView?: google.maps.StreetViewPanorama;
tilt?: number;
zoom?: number;
// Mouse events
onClick?: (e: google.maps.MapMouseEvent) => void;
onDblClick?: (e: google.maps.MapMouseEvent) => void;
onDrag?: () => void;
onDragEnd?: () => void;
onDragStart?: () => void;
onMouseMove?: (e: google.maps.MapMouseEvent) => void;
onMouseOut?: (e: google.maps.MapMouseEvent) => void;
onMouseOver?: (e: google.maps.MapMouseEvent) => void;
onMouseDown?: (e: google.maps.MapMouseEvent) => void;
onMouseUp?: (e: google.maps.MapMouseEvent) => void;
onRightClick?: (e: google.maps.MapMouseEvent) => void;
// Map state change events
onMapTypeIdChanged?: () => void;
onTilesLoaded?: () => void;
onBoundsChanged?: () => void;
onCenterChanged?: () => void;
onHeadingChanged?: () => void;
onIdle?: () => void;
onProjectionChanged?: () => void;
onResize?: () => void;
onTiltChanged?: () => void;
onZoomChanged?: () => void;
// Lifecycle events
onLoad?: (map: google.maps.Map) => void | Promise<void>;
onUnmount?: (map: google.maps.Map) => void | Promise<void>;
}
function GoogleMap(props: GoogleMapProps): JSX.Element;Usage Examples:
import React, { useCallback, useState } from 'react';
import { GoogleMap, LoadScript } from '@react-google-maps/api';
const mapContainerStyle = {
width: '100%',
height: '400px'
};
const center = {
lat: 40.7128,
lng: -74.0060
};
// Basic map
function BasicMap() {
return (
<LoadScript googleMapsApiKey="YOUR_API_KEY">
<GoogleMap
mapContainerStyle={mapContainerStyle}
center={center}
zoom={10}
/>
</LoadScript>
);
}
// Interactive map with events
function InteractiveMap() {
const [mapCenter, setMapCenter] = useState(center);
const [mapZoom, setMapZoom] = useState(10);
const onLoad = useCallback((map: google.maps.Map) => {
console.log('Map loaded:', map);
}, []);
const onClick = useCallback((e: google.maps.MapMouseEvent) => {
if (e.latLng) {
console.log('Clicked at:', e.latLng.toJSON());
setMapCenter(e.latLng.toJSON());
}
}, []);
const onCenterChanged = useCallback(() => {
console.log('Map center changed');
}, []);
return (
<LoadScript googleMapsApiKey="YOUR_API_KEY">
<GoogleMap
mapContainerStyle={mapContainerStyle}
center={mapCenter}
zoom={mapZoom}
options={{
disableDefaultUI: false,
clickableIcons: true,
scrollwheel: true,
}}
onClick={onClick}
onLoad={onLoad}
onCenterChanged={onCenterChanged}
onZoomChanged={() => console.log('Zoom changed')}
/>
</LoadScript>
);
}
// Map with custom styling and options
function StyledMap() {
const mapOptions: google.maps.MapOptions = {
disableDefaultUI: true,
clickableIcons: false,
scrollwheel: false,
disableDoubleClickZoom: true,
mapTypeControl: true,
mapTypeControlOptions: {
style: google.maps.MapTypeControlStyle.HORIZONTAL_BAR,
position: google.maps.ControlPosition.TOP_CENTER,
},
zoomControl: true,
zoomControlOptions: {
position: google.maps.ControlPosition.RIGHT_CENTER,
},
scaleControl: true,
streetViewControl: true,
streetViewControlOptions: {
position: google.maps.ControlPosition.LEFT_TOP,
},
fullscreenControl: false,
styles: [
{
featureType: "all",
elementType: "geometry",
stylers: [{ color: "#242f3e" }]
},
{
featureType: "all",
elementType: "labels.text.stroke",
stylers: [{ color: "#242f3e" }]
},
{
featureType: "all",
elementType: "labels.text.fill",
stylers: [{ color: "#746855" }]
}
]
};
return (
<LoadScript googleMapsApiKey="YOUR_API_KEY">
<GoogleMap
id="styled-map"
mapContainerStyle={mapContainerStyle}
mapContainerClassName="custom-map"
center={center}
zoom={10}
options={mapOptions}
/>
</LoadScript>
);
}GoogleMap is implemented as a class component with an internal functional variant (GoogleMapF) that uses React hooks. However, GoogleMapF is not exported from the main package and is not available for direct use. The main GoogleMap component should be used in all cases.
React hook that provides access to the current Google Map instance from the React Context within child components.
/**
* Hook to access current Google Map instance from context
* Must be used within a GoogleMap component tree
* @returns The Google Maps instance or null if not available
*/
function useGoogleMap(): google.maps.Map | null;Usage Examples:
import React, { useEffect } from 'react';
import { GoogleMap, LoadScript, useGoogleMap } from '@react-google-maps/api';
// Custom component that accesses the map instance
function MapControls() {
const map = useGoogleMap();
useEffect(() => {
if (map) {
// Access map instance directly
console.log('Current map bounds:', map.getBounds());
console.log('Current zoom level:', map.getZoom());
// Add custom controls or modify map programmatically
const controlDiv = document.createElement('div');
controlDiv.innerHTML = '<button>Custom Control</button>';
map.controls[google.maps.ControlPosition.TOP_CENTER].push(controlDiv);
}
}, [map]);
const centerMap = () => {
if (map) {
map.setCenter({ lat: 40.7128, lng: -74.0060 });
map.setZoom(12);
}
};
return (
<div style={{ position: 'absolute', top: 10, left: 10, zIndex: 1 }}>
<button onClick={centerMap}>Center on NYC</button>
</div>
);
}
// Custom marker component that uses map instance
function CustomMapComponent() {
const map = useGoogleMap();
useEffect(() => {
if (map) {
// Create custom marker using native Google Maps API
const marker = new google.maps.Marker({
position: { lat: 40.7128, lng: -74.0060 },
map: map,
title: 'Custom Marker'
});
// Cleanup on unmount
return () => {
marker.setMap(null);
};
}
}, [map]);
return null; // This component doesn't render anything
}
// Usage within GoogleMap
function AppWithMapAccess() {
return (
<LoadScript googleMapsApiKey="YOUR_API_KEY">
<div style={{ position: 'relative' }}>
<GoogleMap
mapContainerStyle={{ width: '100%', height: '400px' }}
center={{ lat: 40.7128, lng: -74.0060 }}
zoom={10}
>
<MapControls />
<CustomMapComponent />
</GoogleMap>
</div>
</LoadScript>
);
}React Context that provides the Google Map instance to child components.
/**
* React Context for sharing Google Map instance
* Used internally by useGoogleMap hook
*/
interface MapContextValue {
map: google.maps.Map | null;
}
const MapContext: React.Context<MapContextValue>;Usage Examples:
import React, { useContext } from 'react';
import { MapContext } from '@react-google-maps/api';
// Direct context usage (useGoogleMap hook is preferred)
function DirectContextUsage() {
const { map } = useContext(MapContext);
React.useEffect(() => {
if (map) {
console.log('Map instance from context:', map);
}
}, [map]);
return null;
}Advanced configuration patterns and map manipulation techniques.
/**
* Advanced map configuration options
*/
interface AdvancedMapOptions extends google.maps.MapOptions {
// Restrict map bounds
restriction?: {
latLngBounds: google.maps.LatLngBounds;
strictBounds?: boolean;
};
// Custom map types
mapTypeControlOptions?: {
mapTypeIds?: (google.maps.MapTypeId | string)[];
style?: google.maps.MapTypeControlStyle;
position?: google.maps.ControlPosition;
};
}Advanced Usage Examples:
// Map with restricted bounds (e.g., for a specific region)
function RestrictedMap() {
const bounds = new google.maps.LatLngBounds(
new google.maps.LatLng(40.4774, -74.2591), // SW corner
new google.maps.LatLng(40.9176, -73.7004) // NE corner
);
const restrictedMapOptions: google.maps.MapOptions = {
restriction: {
latLngBounds: bounds,
strictBounds: false
},
center: { lat: 40.7128, lng: -74.0060 },
zoom: 10
};
return (
<GoogleMap
mapContainerStyle={{ width: '100%', height: '400px' }}
options={restrictedMapOptions}
/>
);
}
// Map with custom map type
function CustomMapTypeExample() {
const onLoad = useCallback((map: google.maps.Map) => {
// Add custom map type
const customMapType = new google.maps.ImageMapType({
getTileUrl: function(coord, zoom) {
return `https://example.com/tiles/${zoom}/${coord.x}/${coord.y}.png`;
},
tileSize: new google.maps.Size(256, 256),
maxZoom: 18,
minZoom: 0,
name: 'Custom'
});
map.mapTypes.set('custom', customMapType);
}, []);
const mapOptions: google.maps.MapOptions = {
mapTypeControlOptions: {
mapTypeIds: ['roadmap', 'satellite', 'hybrid', 'terrain', 'custom'],
style: google.maps.MapTypeControlStyle.HORIZONTAL_BAR,
position: google.maps.ControlPosition.TOP_CENTER
}
};
return (
<GoogleMap
mapContainerStyle={{ width: '100%', height: '400px' }}
center={{ lat: 40.7128, lng: -74.0060 }}
zoom={10}
options={mapOptions}
onLoad={onLoad}
/>
);
}Install with Tessl CLI
npx tessl i tessl/npm-react-google-maps--api