Tổng quan
Hướng dẫn này cho bạn biết cách thêm Bản đồ và Điểm đánh dấu vào ứng dụng React bằng cách sử dụng @googlemaps/react-wrapper và tích hợp bản đồ và điểm đánh dấu vào trạng thái ứng dụng.
Cài đặt @googlemaps/react-wrapper
Cài đặt và sử dụng thư viện @googlemaps/react-wrapper để tự động tải API JavaScript của Maps khi thành phần được hiển thị.
npm install @googlemaps/react-wrapper
Bạn có thể nhập và sử dụng thư viện này với thư viện sau.
import { Wrapper, Status } from "@googlemaps/react-wrapper";
Cách sử dụng cơ bản của thành phần này là để gói các thành phần con phụ thuộc vào API JavaScript của Maps. Thành phần Wrapper
cũng chấp nhận đạo cụ render
để kết xuất các thành phần tải hoặc xử lý lỗi khi tải API JavaScript của Maps.
const render = (status: Status) => {
return <h1>{status}</h1>;
};
<Wrapper apiKey={"YOUR_API_KEY"} render={render}>
<YourComponent/>
</Wrapper>
Thêm thành phần bản đồ
Một thành phần chức năng cơ bản để kết xuất bản đồ có thể sẽ sử dụng các móc phản ứng useRef
, useState
và useEffect
.
Thành phần bản đồ ban đầu sẽ có chữ ký sau.
const Map: React.FC<{}> = () => {};
Vì google.maps.Map
cần có Element
làm tham số hàm dựng, nên bạn cần dùng useRef để duy trì một đối tượng có thể thay đổi và sẽ tồn tại trong suốt thời gian hoạt động của thành phần. Đoạn mã sau sẽ tạo bản đồ trong hook useEffect trong phần nội dung của thành phần 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]);
Móc useEffect
ở trên sẽ chỉ chạy khi ref
thay đổi. Thành phần Map
hiện trả về nội dung sau.
return <div ref={ref} />
Mở rộng thành phần bản đồ bằng các đạo cụ khác
Bạn có thể mở rộng thành phần bản đồ cơ bản bằng cách sử dụng các đề xuất khác cho các tuỳ chọn bản đồ, trình nghe sự kiện và kiểu được áp dụng cho div chứa bản đồ. Đoạn mã sau đây cho thấy giao diện mở rộng của thành phần chức năng này.
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
}) => {}
Đối tượng style
có thể chuyển trực tiếp qua và đặt làm đạo cụ trên div
được hiển thị.
return <div ref={ref} style={style} />;
onClick
, onIdle
và google.maps.MapOptions
yêu cầu hook useEffect
để áp dụng các nội dung cập nhật bắt buộc cho 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]);
Trình nghe sự kiện yêu cầu mã phức tạp hơn một chút để xóa các trình nghe hiện có khi một trình xử lý chuyển qua làm đạo cụ đã được cập nhật.
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]);
Tạo thành phần điểm đánh dấu
Thành phần đánh dấu sử dụng các mẫu tương tự như thành phần bản đồ với các móc useEffect
và 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; };
Thành phần này trả về giá trị rỗng khi google.maps.Map
quản lý thao tác DOM.
Thêm điểm đánh dấu làm thành phần con của bản đồ
Để thêm điểm đánh dấu vào bản đồ, thành phần Marker
sẽ được chuyển tới thành phần Map
bằng cách sử dụng đề xuất children
đặc biệt như sau.
<Wrapper apiKey={"YOUR_API_KEY"}>
<Map center={center} zoom={zoom}>
<Marker position={position} />
</Map>
</Wrapper>
Bạn phải thực hiện một thay đổi nhỏ đối với đầu ra của thành phần Map
để truyền đối tượng google.maps.Map
cho tất cả phần tử con dưới dạng đạo cụ bổ sung.
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 }); } })} </> );
Liên kết bản đồ và trạng thái ứng dụng
Khi sử dụng mẫu ở trên cho các lệnh gọi lại onClick
và onIdle
, bạn có thể mở rộng ứng dụng để tích hợp đầy đủ các thao tác của người dùng như nhấp hoặc xoay bản đồ.
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()); };
Các móc này có thể được tích hợp vào các thành phần biểu mẫu bằng mẫu sau, như được minh họa cho đầu vào vĩ độ.
<label htmlFor="lat">Latitude</label>
<input
type="number"
id="lat"
name="lat"
value={center.lat}
onChange={(event) =>
setCenter({ ...center, lat: Number(event.target.value) })
}
/>
Cuối cùng, ứng dụng theo dõi số lượt nhấp và hiển thị các điểm đánh dấu ở mỗi vị trí lượt nhấp. Mã sau đây sử dụng biến position
để chuyển giá trị LatLng
từ sự kiện nhấp.
{clicks.map((latLng, i) => (<Marker key={i} position={latLng} />))}
Khám phá mã
Bạn có thể khám phá mã mẫu hoàn chỉnh thông qua các sân chơi mã trực tuyến bên dưới hoặc bằng cách sao chép kho lưu trữ git.
Thử mẫu
Mẫu nhân bản
Bạn phải có Git và Node.js để chạy mẫu này trên thiết bị. Làm theo những hướng dẫn này để cài đặt Node.js và NPM. Các lệnh sau đây nhân bản, cài đặt các phần phụ thuộc và khởi động ứng dụng mẫu.
git clone -b sample-react-map https://github.com/googlemaps/js-samples.git
cd js-samples
npm i
npm start
Bạn có thể thử các mẫu khác bằng cách chuyển sang bất kỳ nhánh nào bắt đầu bằng sample-SAMPLE_NAME
.
git checkout sample-SAMPLE_NAME
npm i
npm start