اضافه کردن نقشه و نشانگرها به برنامه React

بررسی اجمالی

این آموزش به شما نشان می دهد که چگونه با استفاده از @googlemaps/react-wrapper یک نقشه و نشانگر را به برنامه React اضافه کنید و نقشه و نشانگرها را در وضعیت برنامه ادغام کنید.

@googlemaps/react-wrapper را نصب کنید

کتابخانه @googlemaps/react-wrapper را برای بارگیری پویا Maps JavaScript API هنگام رندر شدن مؤلفه نصب و استفاده کنید.

npm install @googlemaps/react-wrapper

این کتابخانه با موارد زیر قابل واردات و استفاده است.

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

کاربرد اصلی این مؤلفه، بسته بندی مؤلفه های فرزند است که به Maps JavaScript API وابسته هستند. کامپوننت Wrapper همچنین یک پایه render برای رندر کردن مولفه‌های بارگیری یا رسیدگی به خطاها در بارگیری Maps JavaScript API می‌پذیرد.

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

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

یک جزء نقشه اضافه کنید

یک مؤلفه کاربردی اصلی برای ارائه نقشه احتمالاً از قلاب های useRef ، useState و useEffect React استفاده می کند.

مولفه نقشه اولیه دارای امضای زیر خواهد بود.

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

از آنجایی که google.maps.Map به Element به عنوان پارامتر سازنده نیاز دارد، userRef برای حفظ یک شیء قابل تغییر که در طول عمر جزء باقی بماند، مورد نیاز است. قطعه زیر یک نقشه را در قلاب useEffect در بدنه مؤلفه 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]);

جاوا اسکریپت

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

قلاب useEffect بالا فقط زمانی اجرا می شود که ref تغییر کرده باشد. مؤلفه Map اکنون موارد زیر را برمی گرداند.

return <div ref={ref} />

مولفه نقشه را با لوازم اضافی گسترش دهید

مؤلفه اصلی نقشه را می توان با لوازم اضافی برای گزینه های نقشه، شنوندگان رویداد و سبک های اعمال شده در div حاوی نقشه گسترش داد. کد زیر رابط توسعه یافته این مؤلفه کاربردی را نشان می دهد.

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 می‌تواند مستقیماً از آن عبور کرده و به‌عنوان یک پایه روی div رندر شده تنظیم شود.

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

onClick ، onIdle ، و google.maps.MapOptions به قلاب های useEffect نیاز دارند تا به طور ضروری به روز رسانی ها را در 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]);

جاوا اسکریپت

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

شنوندگان رویداد به کد کمی پیچیده‌تر نیاز دارند تا شنونده‌های موجود را هنگامی که کنترل‌کننده‌ای که به‌عنوان پایه به‌روزرسانی می‌شود، پاک کنند.

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

جاوا اسکریپت

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

یک جزء نشانگر بسازید

مؤلفه نشانگر از الگوهای مشابه به عنوان مؤلفه نقشه با قلاب های useEffect و 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;
};

جاوا اسکریپت

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

جزء null برمی‌گرداند زیرا google.maps.Map دستکاری DOM را مدیریت می‌کند.

نشانگرها را به عنوان جزء فرزند نقشه اضافه کنید

برای افزودن نشانگرها به یک نقشه، مولفه Marker با استفاده از پایه ویژه children مانند زیر به مؤلفه Map منتقل می شود.

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

یک تغییر کوچک در خروجی مولفه Map باید ایجاد شود تا شی google.maps.Map به عنوان یک وسیله اضافی به همه کودکان ارسال شود.

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

جاوا اسکریپت

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

پیوند نقشه و وضعیت برنامه

با استفاده از الگوی بالا برای تماس‌های onClick و onIdle ، برنامه را می‌توان برای ادغام کامل اقدامات کاربر مانند کلیک کردن یا حرکت در نقشه گسترش داد.

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

جاوا اسکریپت

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

این قلاب ها را می توان با استفاده از الگوی زیر که با ورودی عرض جغرافیایی نشان داده شده است، در عناصر فرم ادغام کرد.

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

در نهایت، برنامه کلیک ها را ردیابی می کند و نشانگرها را در هر مکان کلیک نشان می دهد. کد زیر از متغیر position برای ارسال مقدار LatLng از رویداد کلیک استفاده می کند.

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

کد را کاوش کنید

کد نمونه کامل را می توان از طریق زمین های بازی کد آنلاین زیر یا با شبیه سازی مخزن git کاوش کرد.

Sample را امتحان کنید

کلون نمونه

Git و Node.js برای اجرای این نمونه به صورت محلی مورد نیاز هستند. این دستورالعمل ها را برای نصب Node.js و NPM دنبال کنید. دستورات زیر وابستگی ها را شبیه سازی کرده، نصب کرده و نمونه برنامه را شروع می کنند.

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

نمونه های دیگر را می توان با جابجایی به هر شاخه ای که با sample- SAMPLE_NAME شروع می شود امتحان کرد.

  git checkout sample-SAMPLE_NAME
  npm i
  npm start