نظرة عامة
يوضّح لك هذا البرنامج التعليمي كيفية إضافة خريطة ومحدّد موقع إلى تطبيق React باستخدام @googlemaps/react-wrapper ودمج الخريطة والعلامات في حالة التطبيق.
تثبيت @googlemaps/react-wrapper
يمكنك تثبيت مكتبة @googlemaps/react-wrapper واستخدامها لتحميل واجهة برمجة تطبيقات جافا سكريبت للخرائط ديناميكيًا عند عرض المكون.
npm install @googlemaps/react-wrapper
يمكن استيراد هذه المكتبة واستخدامها مع ما يلي.
import { Wrapper, Status } from "@googlemaps/react-wrapper";
الاستخدام الأساسي لهذا المكوِّن هو لف المكوِّنات الثانوية التي تعتمد على واجهة برمجة تطبيقات JavaScript للخرائط. يقبل المكوّن Wrapper
أيضًا دعامة render
لعرض مكونات التحميل أو معالجة الأخطاء في تحميل واجهة برمجة تطبيقات JavaScript للخرائط.
const render = (status: Status) => {
return <h1>{status}</h1>;
};
<Wrapper apiKey={"YOUR_API_KEY"} render={render}>
<YourComponent/>
</Wrapper>
إضافة مكوِّن خريطة
هناك مكوّن وظيفي أساسي لعرض خريطة، ومن المرجح أن يستفيد من الخطّاطات المتفاعلة في useRef
وuseState
وuseEffect
..
سيكون للمكوّن الأساسي في الخريطة التوقيع التالي.
const Map: React.FC<{}> = () => {};
نظرًا لأن google.maps.Map
تتطلب Element
كمعلمة دالة إنشاء، فإن useRef مطلوبة للحفاظ على كائن قابل للتغيير يدوم طوال فترة عمل المكوِّن. ينشئ المقتطف التالي خريطة ضمن هوك 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]);
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]);
لن يتم تشغيل هوك 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]);
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]);
تتطلب أدوات معالجة الأحداث رمزًا أكثر تعقيدًا قليلاً لمحو المستمعين الحاليين عند تحديث المعالج كدعائم.
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]);
إنشاء مكوِّن علامة
يستخدم مكوِّن العلامة أنماطًا مشابهة لمكوِّن الخريطة، مع عناصر ربط 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; };
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.
إضافة علامات كمكوّن فرعي للخريطة
لإضافة العلامات إلى خريطة، سيتم تمرير المكون Marker
إلى المكون Map
باستخدام دعامة children
الخاصة كما هو موضح في ما يلي.
<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 }); } })} </> );
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 }); } })} </> );
ربط الخريطة وحالة التطبيق
باستخدام النمط أعلاه لمعاودة الاتصال 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()); };
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()); };
يمكن دمج هذه العناصر في عناصر النموذج باستخدام النمط التالي كما هو موضح في إدخال خط العرض.
<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.
تجربة النموذج
استنساخ النموذج
يجب استخدام 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