Swyfte
Swyfte

Reputation: 41

How do I make an infowindow appear when the user clicks the marker, while using a functional component?

The Google Maps API library I am using for this is https://github.com/JustFly1984/react-google-maps-api

What I have been asked to create is a map with multiple markers, each of which can be clicked on to open an InfoWindow centred on that marker. Much like the AirBnB search page, with the map on one side results on the other.

However, I seem to only be able to have an InfoWindow that is open at the loading of the page and then can't be opened again.

My research so far has generally shown that I would need to completely redo this component as a class instead. Although I don't really understand the class based model of components, so ideally I wouldn't have to mess around with that.

Is there a way to make the desired effect without reworking my program entirely?

This is the code for the component, in case it is relevant

import styles from '../../styles/Home.module.css';
import { Marker, LoadScriptNext, GoogleMap, InfoWindow } from '@react-google-maps/api';
import { Fragment, React } from 'react';
import { Typography } from '@material-ui/core';

export default function MapPanel(props) {
  return (
    <Fragment>
      <LoadScriptNext id='google-map-example' googleMapsApiKey="MYAPIKEY">
        <GoogleMap mapContainerStyle={{ width: "100%", height: "800px" }}
          id='google-map'
          center={props.centre}
          heading="0"
          zoom={12}>
          {addMarkers(props.markerList)}
        </GoogleMap>
      </LoadScriptNext>
    </Fragment>
  );
}

function addMarkers(markerList) {
  if (markerList != undefined) {
    return (markerList.map((marker, index) => makeMarker(marker, index)))
  }
}

function makeMarker(marker, index) {
  const handleClick = () => {
    console.log(`${marker.title} marker clicked`);
  }
  return (
    <Marker id={index} position={marker.latLong} title={marker.title} onClick={handleClick}>
      <InfoWindow id='Test' position={marker.latLong}>
        <Typography variant='body2'>{marker.text}</Typography>
      </InfoWindow>
    </Marker>
  );
}

Upvotes: 0

Views: 948

Answers (1)

Ricky Cuarez
Ricky Cuarez

Reputation: 768

To achieve your goal you would want to use states in your application. But since you want to deal with it using Function components, you would need to make use of react hooks to use states.

Here is a working sample for your reference: https://stackblitz.com/edit/marker-with-infowindow-react-api-o6357y


    import ReactDOM from "react-dom";
    import React from "react";
    import {
      GoogleMap,
      Marker,
      InfoWindow,
      LoadScript
    } from "@react-google-maps/api";
    import data from "./data.json";
    
    const { useState } = React;
    const containerStyle = {
      width: "400px",
      height: "400px"
    };
    
    const center = { lat: 40.712775, lng: -74.005973 };
    
    function Map() {
      const [infoWindowID, setInfoWindowID] = useState("");
      let markers;
    
      if (data !== null) {
        markers = data.map((location, i) => {
          const marker = { lat: location.lat, lng: location.lng };
          const index = i + 1;
          return (
            <Marker
              key={index}
              position={marker}
              label={index.toString()}
              onClick={() => {
                setInfoWindowID(index);
              }}
            >
              {infoWindowID === index && (
                <InfoWindow>
                  <span>Something {index}</span>
                </InfoWindow>
              )}
            </Marker>
          );
        });
      }
      return (
        <LoadScript googleMapsApiKey="YOUR_API_KEY">
          <GoogleMap mapContainerStyle={containerStyle} center={center} zoom={10}>
            {markers}
          </GoogleMap>
        </LoadScript>
      );
    }
    
    export default React.memo(Map);

Upvotes: 1

Related Questions