Tepki Uygulamasına Harita ve İşaretçiler Ekleme

Genel bakış

Bu eğiticide, @googlemaps/react-wrapper ile bir React uygulamasına Harita ve İşaretçi eklemeyi, harita ve işaretçileri uygulama durumuna entegre etmeyi öğrenebilirsiniz.

@googlemaps/react-wrapper uygulamasını yükleyin

Bileşen oluşturulduğunda Maps JavaScript API'yi dinamik olarak yüklemek için @googlemaps/react-wrapper kitaplığını yükleyin ve kullanın.

npm install @googlemaps/react-wrapper

Bu kitaplık içe aktarılabilir ve aşağıdakilerle kullanılabilir.

import { Wrapper, Status } from "@googlemaps/react-wrapper";

Bu bileşenin temel kullanımı, Maps JavaScript API'ye bağlı olan alt bileşenleri sarmalamaktır. Wrapper bileşeni, yükleme bileşenlerini oluşturmak veya Maps JavaScript API'yi yüklerken hataları ele almak için kullanılan bir render özelliğini de kabul eder.

const render = (status: Status) => {
  return <h1>{status}</h1>;
};

<Wrapper apiKey={"YOUR_API_KEY"} render={render}>
  <YourComponent/>
</Wrapper>

Harita bileşeni ekleme

Harita oluşturmak için temel bir işlevde büyük olasılıkla useRef, useState ve useEffect Tepki kancaları kullanılır.

İlk harita bileşeninde aşağıdaki imza bulunur.

const Map: React.FC<{}> = () => {};

google.maps.Map, oluşturucu parametresi olarak Element gerektirdiğinden bileşenin kullanım ömrü boyunca değişmeyecek, değişmeyen bir nesnenin korunması için useRef gereklidir. Aşağıdaki snippet, Map bileşeninin gövdesinde useEffect kancasındaki bir haritayı somutlaştırır.

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]);

Yukarıdaki useEffect kancası yalnızca ref değiştiğinde çalışır. Map bileşeni artık aşağıdakileri döndürür.

return <div ref={ref} />

Ek bileşeni olan harita bileşenini genişlet

Temel harita bileşeni; harita seçenekleri, etkinlik işleyiciler ve haritayı içeren div'e uygulanan stiller için ek sahneler ile genişletilebilir. Aşağıdaki kod, bu işlevsel bileşenin genişletilmiş arayüzünü göstermektedir.

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
}) => {}

style nesnesi doğrudan iletilebilir ve oluşturulan div üzerinde bir özellik olarak ayarlanabilir.

return <div ref={ref} style={style} />;

onClick, onIdle ve google.maps.MapOptions, güncellemeleri zorunlu olarak google.maps.Map için uygulamak üzere useEffect kanca gerektirir.

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]);

Ürün olarak iletilen bir işleyici güncellendiğinde mevcut dinleyicileri temizlemek için etkinlik dinleyicileri biraz daha karmaşık koda ihtiyaç duyar.

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]);

İşaretçi bileşeni oluşturma

İşaretçi bileşeni, useEffect ve useState kancalarına sahip harita bileşeniyle benzer kalıpları kullanır.

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;
};

google.maps.Map, DOM manipülasyonunu yönettiği için bileşen null döndürür.

İşaretçileri haritanın alt bileşeni olarak ekleme

İşaretçileri bir haritaya eklemek için Marker bileşeni, aşağıdaki gibi özel children donanımı kullanılarak Map bileşenine iletilir.

<Wrapper apiKey={"YOUR_API_KEY"}>
  <Map center={center} zoom={zoom}>
    <Marker position={position} />
  </Map>
</Wrapper>

google.maps.Map nesnesinin tüm alt öğelere ek bir özellik olarak iletilmesi için Map bileşeninin çıkışında küçük bir değişiklik yapılması gerekir.

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 });
      }
    })}
  </>
);

Bağlantı haritası ve uygulama durumu

Uygulama, onClick ve onIdle geri çağırmaları için yukarıdaki deseni kullanarak, haritayı tıklama veya kaydırma gibi kullanıcı işlemlerini tam olarak entegre etmek üzere genişletilebilir.

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());
};

Bu kancalar, enlem girişinde gösterildiği gibi aşağıdaki desen kullanılarak form öğelerine entegre edilebilir.

<label htmlFor="lat">Latitude</label>
<input
  type="number"
  id="lat"
  name="lat"
  value={center.lat}
  onChange={(event) =>
    setCenter({ ...center, lat: Number(event.target.value) })
  }
/>

Son olarak uygulama, tıklamaları izler ve her tıklama konumunda işaretçiler oluşturur. Aşağıdaki kod, tıklama etkinliğinden LatLng değerini iletmek için position değişkenini kullanır.

{clicks.map((latLng, i) => (<Marker key={i} position={latLng} />))}

Kodu keşfedin

Örnek kodun tamamı, aşağıdaki online kod oyun alanları aracılığıyla veya git deposunu klonlanarak bulunabilir.

Örneği Deneyin

Örneği Klonla

Bu örneği yerel olarak çalıştırmak için Git ve Node.js gereklidir. Node.js ve NPM'yi yüklemek için bu talimatları uygulayın. Aşağıdaki komutlar klonlanır, bağımlıları yükleyin ve örnek uygulamayı başlatın.

  git clone -b sample-react-map https://github.com/googlemaps/js-samples.git
  cd js-samples
  npm i
  npm start

Diğer örnekler, sample-SAMPLE_NAME ile başlayan herhangi bir dala geçiş yapılarak denenebilir.

  git checkout sample-SAMPLE_NAME
  npm i
  npm start