@vis.gl/react-google-maps

repository·main·Indexed 23 days ago

https://github.com/visgl/react-google-maps

A TypeScript/JavaScript library providing React components and hooks for the Google Maps JavaScript API. It offers a reactive wrapper around the imperative Google Maps API, supporting both uncontrolled and fully controlled map states, as well as integrations for Advanced Markers, autocomplete functionality, and deck.gl overlays.

Tokens
56.3K
Snippets
159
Records
273
Agent score
83%

What's inside @vis.gl/react-google-maps

  1. Overview of @vis.gl/react-google-maps capabilities

    main

    The @vis.gl/react-google-maps library provides a TypeScript/JavaScript interface for the Google Maps JavaScript API within React. It includes:

    • React Components: For rendering maps, markers, infowindows, geometry overlays (circles, polylines, polygons), and photorealistic 3D maps.
    • Hooks: To access Google Maps JavaScript API Services and Libraries.
  2. Introduction to @vis.gl/react-google-maps

    main
    @vis.gl/react-google-maps is a collection of React components and hooks designed for the Google Maps JavaScript API. It provides a reactive wrapper around the imperative Google Maps API, inspired by the integration pattern used in react-map-gl.
  3. Use the Google Maps Extended Component Library

    main

    The Google Maps Platform’s Extended Component Library is a set of Web Components designed to simplify building complex map UIs. It encapsulates boilerplate code, best practices, and responsive design into single HTML elements.

    This example demonstrates a locations services web app using the following components:

    • SplitLayout
    • OverlayLayout
    • PlacePicker
    • PlaceOverview
    • IconButton
    • PlaceDataProvider
    • PlaceReviews

    Note: The library is open source and is not governed by Google Maps Platform Support Technical Support Services Guidelines, SLA, or Deprecation Policy. Bugs and feature requests should be filed on the library's GitHub repository.

  4. Enable Map Instance Caching with `reuseMaps`

    main

    To avoid unnecessary costs from the Google Maps JavaScript API (which charges per map-view/constructor call), you can enable map instance caching.

    When the reuseMaps prop is set to true, the component will attempt to reuse existing map instances that share the same:

    • mapId
    • colorScheme
    • renderingType

    Warning: Map caching is currently experimental. If you encounter issues when reusing maps with different options, consider disabling this feature.

  5. Controlled vs Uncontrolled camera props in `<Map>`

    main

    The <Map> component allows you to manage camera parameters (center, zoom, heading, and tilt) using either controlled or uncontrolled patterns.

    Uncontrolled Mode

    Use defaultCenter and defaultZoom to set the initial state. These values are only applied during the map's first initialization. Subsequent user interactions will change the map state without needing to update props.

    const UncontrolledMap = () => {
      return <Map defaultCenter={{lat: 40.7, lng: -74}} defaultZoom={12}></Map>;
    };

    Controlled Mode

    Use center and zoom to keep the map synchronized with your application state. When a user interacts with the map, the onCameraChanged event is fired, providing the new camera parameters via ev.detail. You must then update your state to reflect these changes.

    import {MapCameraChangedEvent, MapCameraProps} from '@vis.gl/react-google-maps';
    
    const INITIAL_CAMERA = {
      center: {lat: 40.7, lng: -74},
      zoom: 12
    };
    
    const ControlledMap = () => {
      const [cameraProps, setCameraProps] =
        useState<MapCameraProps>(INITIAL_CAMERA);
      const handleCameraChange = useCallback((ev: MapCameraChangedEvent) =>
        setCameraProps(ev.detail)
      );
    
      return <Map {...cameraProps} onCameraChanged={handleCameraChange}></Map>;
    };

    Externally Controlled Mode

    By setting the controlled prop to true, the map disables all user control inputs and will only render what is explicitly specified in the camera props.

  6. Best practices for writing examples

    main

    When writing examples, adhere to these principles to ensure they are useful for users and maintainable:

    • Focus: Demonstrate a single feature or a specific set of features comprehensively. Avoid cluttering the code with unrelated concepts (e.g., hide data preparation logic).
    • Organization: Place the 'gist' or core logic of the example at the top of the main source file, as users typically read from top to bottom.
    • Reusability: Write code for proposed features in a reusable way so users can easily copy components or hooks into their own projects.
    • Decoupling: Minimize dependencies in your example components/hooks and avoid bundler-specific features like direct CSS imports or environment variables to ensure portability.
  7. Implement Custom Autocomplete with `useAutocompleteSuggestions`

    main

    For full control over the UI and logic, you can build a custom autocomplete implementation using the new Autocomplete Data API.

    This approach involves retrieving predictions for the current value of an input field. The logic for this can be encapsulated in a custom hook. In this example, the logic is provided via the useAutocompleteSuggestions hook, which can be copied into your own project to power custom input fields or third-party UI components.

  8. Manage Map Instance Caching with `reuseMaps`

    main

    Changing certain props like mapId, colorScheme, or renderingType requires the internal google.maps.Map instance to be recreated, which incurs additional costs.

    To optimize performance and cost when dynamically switching between different Map IDs, color schemes, or rendering types, set the reuseMaps prop to true. This enables map-instance caching, allowing the component to reuse existing instances that share the same configuration.

  9. Customize `<AdvancedMarker>` appearance

    main

    You can customize the marker in two primary ways:

    1. Using the <Pin> component: Pass a <Pin> component as a child to customize colors (background, border, glyph).
    2. Using Custom HTML: Pass any other React element (like <img>, <div>, or SVG) as a child. When using custom HTML, a "content element" (div) is created via a React portal.

    Note on Positioning: When using custom HTML, the marker is positioned with the position coordinate at the bottom center of the content element by default. To change this, use the anchorPoint prop.

    import {AdvancedMarker, AdvancedMarkerAnchorPoint} from '@vis.gl/react-google-maps';
    
    // Using a custom anchor point (e.g., top-left)
    <AdvancedMarker position={...} anchorPoint={AdvancedMarkerAnchorPoint.TOP_LEFT}>
        <img src={markerImage} />
    </AdvancedMarker>
  10. Manage controlled vs uncontrolled `<Circle>` state

    main

    When using editable or draggable props, you must choose between an uncontrolled or controlled pattern:

    Uncontrolled

    Use defaultCenter and defaultRadius to set initial values. The user can then modify the circle freely without needing to sync state back to React.

    <Circle
      defaultCenter={{lat: 53.5, lng: 10}}
      defaultRadius={1000}
      editable
      draggable
    />

    Controlled

    Use center and radius to force the circle to reflect your React state. Crucially, you must use onCenterChanged and onRadiusChanged to update your state, otherwise the circle will snap back to its original position during interaction.

    const [center, setCenter] = useState({lat: 53.5, lng: 10});
    const [radius, setRadius] = useState(1000);
    
    <Circle
      center={center}
      radius={radius}
      editable
      draggable
      onCenterChanged={c => c && setCenter({lat: c.lat(), lng: c.lng()})}
      onRadiusChanged={setRadius}
    />;
    // Uncontrolled - initial values only, users can edit freely
    <Circle
      defaultCenter={{lat: 53.5, lng: 10}}
      defaultRadius={1000}
      editable
      draggable
    />
    
    // Controlled - value always reflects props
    <Circle center={center} radius={radius} editable draggable />