Panoramica
Questo tutorial mostra come aggiungere una mappa e un indicatore a un'applicazione React utilizzando @googlemaps/react-wrapper e integrare la mappa e gli indicatori nello stato dell'applicazione.
Installa @googlemaps/react-wrapper
Installa e utilizza la libreria @googlemaps/react-wrapper per caricare dinamicamente l'API Maps JavaScript quando viene eseguito il rendering del componente.
npm install @googlemaps/react-wrapper
La libreria può essere importata e utilizzata con quanto segue.
import { Wrapper, Status } from "@googlemaps/react-wrapper";
L'utilizzo di base di questo componente consiste nel wrapping dei componenti secondari che dipendono dall'API JavaScript di Maps. Il componente Wrapper
accetta anche una proposta di render
per il rendering dei componenti o per la gestione degli errori di caricamento dell'API Maps JavaScript.
const render = (status: Status) => {
return <h1>{status}</h1>;
};
<Wrapper apiKey={"YOUR_API_KEY"} render={render}>
<YourComponent/>
</Wrapper>
Aggiungere un componente della mappa
È probabile che un componente funzionale di base per eseguire il rendering di una mappa utilizzi gli hook di reazione useRef
, useState
e useEffect
.
Il componente mappa iniziale avrà la seguente firma.
const Map: React.FC<{}> = () => {};
Poiché google.maps.Map
richiede un Element
come parametro costruttore, è necessario useRef per mantenere un oggetto modificabile che persisterà per tutta la durata del componente. Il seguente snippet crea un'istanza di una mappa all'interno del hook useEffetto nel corpo del componente Map
.
TypeScript
const ref = React.useRef<HTMLDivElement>(null); const [map, setMap] = React.useState<google.maps.Map>(); React.useEffect(() => { if (ref.current && !map) { setMap(new window.google.maps.Map(ref.current, {})); } }, [ref, map]);
JavaScript
const ref = React.useRef(null); const [map, setMap] = React.useState(); React.useEffect(() => { if (ref.current && !map) { setMap(new window.google.maps.Map(ref.current, {})); } }, [ref, map]);
Il hook useEffect
precedente verrà eseguito solo quando ref
è cambiato. Il componente Map
restituisce ora il seguente.
return <div ref={ref} />
Estendi il componente mappa con altri oggetti
Il componente mappa di base può essere ampliato con ulteriori oggetti di scena per le opzioni della mappa, i listener di eventi e gli stili applicati al div contenente la mappa. Il codice seguente mostra l'interfaccia espansa di questo componente funzionale.
interface MapProps extends google.maps.MapOptions {
style: { [key: string]: string };
onClick?: (e: google.maps.MapMouseEvent) => void;
onIdle?: (map: google.maps.Map) => void;
}
const Map: React.FC<MapProps> = ({
onClick,
onIdle,
children,
style,
...options
}) => {}
L'oggetto style
può essere passato direttamente e impostato come un oggetto di scena sul valore di div
visualizzato.
return <div ref={ref} style={style} />;
onClick
, onIdle
e google.maps.MapOptions
richiedono useEffect
hook per applicare imperativamente gli aggiornamenti a google.maps.Map
.
TypeScript
// because React does not do deep comparisons, a custom hook is used // see discussion in https://github.com/googlemaps/js-samples/issues/946 useDeepCompareEffectForMaps(() => { if (map) { map.setOptions(options); } }, [map, options]);
JavaScript
// because React does not do deep comparisons, a custom hook is used // see discussion in https://github.com/googlemaps/js-samples/issues/946 useDeepCompareEffectForMaps(() => { if (map) { map.setOptions(options); } }, [map, options]);
I listener di eventi richiedono un codice leggermente più complesso per cancellare i listener esistenti quando viene gestito un gestore che è stato aggiornato.
TypeScript
React.useEffect(() => { if (map) { ["click", "idle"].forEach((eventName) => google.maps.event.clearListeners(map, eventName) ); if (onClick) { map.addListener("click", onClick); } if (onIdle) { map.addListener("idle", () => onIdle(map)); } } }, [map, onClick, onIdle]);
JavaScript
React.useEffect(() => { if (map) { ["click", "idle"].forEach((eventName) => google.maps.event.clearListeners(map, eventName) ); if (onClick) { map.addListener("click", onClick); } if (onIdle) { map.addListener("idle", () => onIdle(map)); } } }, [map, onClick, onIdle]);
Creare un componente dell'indicatore
Il componente indicatore utilizza pattern simili a quelli del componente mappa con hook useEffect
e useState
.
TypeScript
const Marker: React.FC<google.maps.MarkerOptions> = (options) => { const [marker, setMarker] = React.useState<google.maps.Marker>(); React.useEffect(() => { if (!marker) { setMarker(new google.maps.Marker()); } // remove marker from map on unmount return () => { if (marker) { marker.setMap(null); } }; }, [marker]); React.useEffect(() => { if (marker) { marker.setOptions(options); } }, [marker, options]); return null; };
JavaScript
const Marker = (options) => { const [marker, setMarker] = React.useState(); React.useEffect(() => { if (!marker) { setMarker(new google.maps.Marker()); } // remove marker from map on unmount return () => { if (marker) { marker.setMap(null); } }; }, [marker]); React.useEffect(() => { if (marker) { marker.setOptions(options); } }, [marker, options]); return null; };
Il componente restituisce null poiché google.maps.Map
gestisce la manipolazione del DOM.
Aggiungere indicatori come componente secondario della mappa
Per aggiungere gli indicatori a una mappa, il componente Marker
viene passato al componente Map
utilizzando l'elemento speciale children
speciale, come nell'esempio seguente.
<Wrapper apiKey={"YOUR_API_KEY"}>
<Map center={center} zoom={zoom}>
<Marker position={position} />
</Map>
</Wrapper>
È necessario apportare una piccola modifica all'output del componente Map
per passare l'oggetto google.maps.Map
a tutti i componenti secondari come elemento di scena aggiuntivo.
TypeScript
return ( <> <div ref={ref} style={style} /> {React.Children.map(children, (child) => { if (React.isValidElement(child)) { // set the map prop on the child component // @ts-ignore return React.cloneElement(child, { map }); } })} </> );
JavaScript
return ( <> <div ref={ref} style={style} /> {React.Children.map(children, (child) => { if (React.isValidElement(child)) { // set the map prop on the child component // @ts-ignore return React.cloneElement(child, { map }); } })} </> );
Collega mappa e stato dell'applicazione
Utilizzando il pattern riportato sopra per i callback onClick
e onIdle
, l'applicazione può essere estesa per integrare completamente le azioni degli utenti, come fare clic sulla mappa o eseguire una panoramica.
TypeScript
const [clicks, setClicks] = React.useState<google.maps.LatLng[]>([]); const [zoom, setZoom] = React.useState(3); // initial zoom const [center, setCenter] = React.useState<google.maps.LatLngLiteral>({ lat: 0, lng: 0, }); const onClick = (e: google.maps.MapMouseEvent) => { // avoid directly mutating state setClicks([...clicks, e.latLng!]); }; const onIdle = (m: google.maps.Map) => { console.log("onIdle"); setZoom(m.getZoom()!); setCenter(m.getCenter()!.toJSON()); };
JavaScript
const [clicks, setClicks] = React.useState([]); const [zoom, setZoom] = React.useState(3); // initial zoom const [center, setCenter] = React.useState({ lat: 0, lng: 0, }); const onClick = (e) => { // avoid directly mutating state setClicks([...clicks, e.latLng]); }; const onIdle = (m) => { console.log("onIdle"); setZoom(m.getZoom()); setCenter(m.getCenter().toJSON()); };
Questi ganci possono essere integrati negli elementi del modulo utilizzando il seguente schema, come dimostrato dall'input della latitudine.
<label htmlFor="lat">Latitude</label>
<input
type="number"
id="lat"
name="lat"
value={center.lat}
onChange={(event) =>
setCenter({ ...center, lat: Number(event.target.value) })
}
/>
Infine, l'applicazione monitora i clic ed esegue il rendering degli indicatori in ogni posizione di clic. Il seguente codice utilizza la variabile position
per trasmettere il valore LatLng
dall'evento di clic.
{clicks.map((latLng, i) => (<Marker key={i} position={latLng} />))}
Esplora il codice
Il codice campione completo può essere esplorato attraverso le aree giochi online di seguito o clonando il repository Git.
Prova anteprima
Clona un campione
Sono richiesti Git e Node.js per eseguire questo esempio in locale. Per installare Node.js e NPM, segui queste istruzioni. I seguenti comandi clonano, installano le dipendenze e avviano l'applicazione di esempio.
git clone -b sample-react-map https://github.com/googlemaps/js-samples.git
cd js-samples
npm i
npm start
È possibile provare altri esempi passando a qualsiasi ramo che inizia con sample-SAMPLE_NAME
.
git checkout sample-SAMPLE_NAME
npm i
npm start