reactjsgoogle-places-apisearch-box

Implementing Places Search Box in ReactJS


I need to implement the Google Places Search Box using the Google Place Autocomplete feature as it is shown here. And it should be allow the user to select a location from the search box.

The sample code is in JavaScript and what I need is to implement it in my react application.

import React, { useEffect, useRef, useState } from 'react';
import { LoadScript } from '@react-google-maps/api';

export default function GoogleMapSearchBox() {
  const mapRef = useRef(null);
  const [map, setMap] = useState(null);
  const [searchBox, setSearchBox] = useState(null);

  const handlePlacesChanged = () => {
    const places = searchBox.getPlaces();

    if (places.length == 0) {
      return;
    }

    const bounds = new google.maps.LatLngBounds();

    places.forEach((place) => {
      if (!place.geometry || !place.geometry.location) {
        console.log('Returned place contains no geometry');
        return;
      }

      const markers = mapRef.current.getMarkers();
      markers.forEach((marker) => {
        marker.setMap(null);
      });

      const marker = new google.maps.Marker({
        map,
        title: place.name,
        position: place.geometry.location,
      });
      mapRef.current.addMarker(marker);

      if (place.geometry.viewport) {
        bounds.union(place.geometry.viewport);
      } else {
        bounds.extend(place.geometry.location);
      }
    });

    map.fitBounds(bounds);
  };

  useEffect(() => {
    if (!mapRef.current) return;

    const mapInstance = new google.maps.Map(mapRef.current, {
      center: { lat: -33.8688, lng: 151.2195 },
      zoom: 13,
      mapTypeId: 'roadmap',
    });

    setMap(mapInstance);

    const input = document.getElementById('pac-input');
    const searchBoxInstance = new google.maps.places.SearchBox(input);

    mapInstance.controls[google.maps.ControlPosition.TOP_LEFT].push(input);

    mapInstance.addListener('bounds_changed', () => {
      searchBoxInstance.setBounds(mapInstance.getBounds());
    });

    setSearchBox(searchBoxInstance);
  }, []);

  return (
    <div style={{ height: '300px', width: '100%' }}>
      <LoadScript
        googleMapsApiKey={process.env.GOOGLE_API_KEY}
        libraries={['places']}
      >
        <div id="map" ref={mapRef} />
      </LoadScript>
      <input
        className="mt-5"
        type="text"
        id="pac-input"
        placeholder="Search for a place"
      />
    </div>
  );
}

So far I have done this and need to know what I am doing wrong.


Solution

  • "use client";
    import React, { useState } from "react";
    import {
        useLoadScript,
        GoogleMap,
        Marker as AdvancedMarkerElement,
    } from "@react-google-maps/api";
    
    const libraries = ["places"]; 
    
    const GoogleMapComp = ({ className }) => {
        const [map, setMap] = useState(null);
        const [location, setLocation] = useState({
            lat: 6.925187004369271,
            lng: 79.86128293151192,
        });
    
        const { isLoaded, loadError } = useLoadScript({
            googleMapsApiKey: process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY,
            libraries,
            loading: "async",
        });
    
        const handleMapLoad = (mapInstance) => {
            setMap(mapInstance);
        };
    
        const handleClick = (event) => {
            setLocation({
                lat: event.latLng.lat(),
                lng: event.latLng.lng(),
            });
        };
    
        if (loadError) return "Error loading maps";
        if (!isLoaded) return "Loading maps";
    
        return (
            <div className={className}>
                <GoogleMap
                    mapContainerStyle={{ width: "100%", height: "100%" }}
                    zoom={13}
                    center={{ lat: 6.925187004369271, lng: 79.86128293151192 }}
                    onLoad={handleMapLoad}
                    onClick={handleClick}
                >
                    {location && <AdvancedMarkerElement position={location} />}
                </GoogleMap>
            </div>
        );
    };
    
    export default GoogleMapComp;