Omówienie
W tym samouczku pokazujemy, jak dodać mapę i znacznik do aplikacji React przy użyciu @googlemaps/react-wrapper i zintegrować mapę i znaczniki ze stanem aplikacji.
Zainstaluj @googlemaps/react-wrapper
Zainstaluj i użyj biblioteki @googlemaps/react-wrapper, aby dynamicznie wczytywać interfejs Maps JavaScript API podczas renderowania komponentu.
npm install @googlemaps/react-wrapper
Tę bibliotekę można importować i używać w przypadku następujących elementów:
import { Wrapper, Status } from "@googlemaps/react-wrapper";
Podstawowym zastosowaniem tego komponentu jest opakowywanie komponentów podrzędnych zależnych od interfejsu API JavaScript Map Google. Komponent Wrapper
akceptuje również propozycję render
do renderowania komponentów wczytywania lub obsługi błędów podczas wczytywania interfejsu Maps JavaScript API.
const render = (status: Status) => {
return <h1>{status}</h1>;
};
<Wrapper apiKey={"YOUR_API_KEY"} render={render}>
<YourComponent/>
</Wrapper>
Dodaj komponent mapy
Podstawowym elementem służącym do renderowania mapy jest prawdopodobnie wykorzystanie useRef
, useState
i useEffect
haków reakcji.
Początkowy komponent mapy będzie miał następujący podpis.
const Map: React.FC<{}> = () => {};
google.maps.Map
wymaga parametru Element
jako konstruktora, dlatego parametr useRef jest potrzebny do utrzymania obiektu zmiennego, który zostanie zachowany przez cały okres życia komponentu. Ten fragment kodu tworzy instancję mapy w obiekcie useResult w treści komponentu 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]);
Podany powyżej hak useEffect
zostanie uruchomiony tylko wtedy, gdy zmieni się ref
. Komponent Map
zwraca teraz te wartości.
return <div ref={ref} />
Powiększ komponent mapy o dodatkowe rekwizyty
Podstawowy komponent mapy można rozszerzyć o dodatkowe rekwizyty opcji opcji, detektorów zdarzeń i stylów zastosowanych do elementu div zawierającego mapę. Poniżej znajduje się rozwinięty interfejs tego komponentu funkcjonalnego.
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
}) => {}
Obiekt style
może zostać przekazany bezpośrednio i ustawiony jako wskazówka na renderowanym obiekcie div
.
return <div ref={ref} style={style} />;
onClick
, onIdle
i google.maps.MapOptions
wymagają punktów zaczepienia useEffect
, aby zastosować aktualizacje do 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]);
Po zaktualizowaniu procedury obsługi rekwizytów detektory zdarzeń wymagają nieco bardziej złożonego kodu, by można było ich usunąć.
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]);
Tworzenie komponentu znacznika
Komponent Znaczniki korzysta z podobnych wzorców co komponent mapy z punktami zaczepieniami useEffect
i 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; };
Komponent zwraca wartość null, gdy google.maps.Map
zarządza manipulacją DOM.
Dodawanie znaczników jako komponentu podrzędnego mapy
Aby dodać znaczniki do mapy, komponent Marker
zostanie przekazany do komponentu Map
za pomocą specjalnej właściwości children
, jak w poniższym przykładzie.
<Wrapper apiKey={"YOUR_API_KEY"}>
<Map center={center} zoom={zoom}>
<Marker position={position} />
</Map>
</Wrapper>
Należy wprowadzić niewielką zmianę w danych wyjściowych komponentu Map
, aby przekazać obiekt google.maps.Map
do wszystkich elementów podrzędnych w ramach dodatkowej właściwości.
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 }); } })} </> );
Mapa linku i stan aplikacji
Używając powyższego wzorca w wywołaniach zwrotnych onClick
i onIdle
, aplikację można rozszerzyć, aby w pełni zintegrować działania użytkownika, takie jak kliknięcie lub przesunięcie mapy.
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()); };
Punkty te możesz integrować z elementami formularza, korzystając z podanego niżej wzoru, tak jak jest to podane w polu szerokości.
<label htmlFor="lat">Latitude</label>
<input
type="number"
id="lat"
name="lat"
value={center.lat}
onChange={(event) =>
setCenter({ ...center, lat: Number(event.target.value) })
}
/>
Na koniec aplikacja śledzi kliknięcia i renderuje znaczniki przy każdej lokalizacji kliknięcia. Ten kod korzysta ze zmiennej position
do przekazywania wartości LatLng
ze zdarzenia kliknięcia.
{clicks.map((latLng, i) => (<Marker key={i} position={latLng} />))}
Przeglądaj kod
Pełny przykładowy kod można znaleźć w placach zabaw online poniżej lub sklonować repozytorium git.
Fragment
Klonuj próbkę
Do uruchomienia tego przykładu wymagane są Git i Node.js. Aby zainstalować Node.js i NPM, postępuj zgodnie z tymi instrukcjami. Poniższe polecenia sklonują, instalują zależności i uruchamiają przykładową aplikację.
git clone -b sample-react-map https://github.com/googlemaps/js-samples.git
cd js-samples
npm i
npm start
Inne przykłady można wypróbować, przełączając się na dowolną gałąź zaczynającą się od sample-SAMPLE_NAME
.
git checkout sample-SAMPLE_NAME
npm i
npm start