Search code examples
reactjsgraphqlgatsbycontentful

Can I query GraphQL inside Google Map component?


I'm playing around with Gatsby/Contentful and Google Maps.

I've created this component:

import React from 'react'
import { GoogleMap, Marker, InfoWindow } from 'react-google-maps'

const Map = (props) => {

    return (

        <GoogleMap
            defaultZoom={12}
            defaultCenter={{
                lat: 34.0522,
                lng: 118.2437
            }}
            >

            <Marker
                onMouseOver={() => {
                    setInfoWindow(true)
                }}
                onClick={() => props.setmodal(true)}
                position={{
                    lat: 34.0522,
                    lng: 118.2437
                }}
            />

        </GoogleMap>
    )
}

export default Map;

The map is showing and everything works fine. I've tried to access my Contentful data using this approach, but getting an error that allContentfulLocations are undefined. How can I query my Contentful data inside Google Maps?

Here was my approach which is failing.

import React from 'react'
import { GoogleMap, Marker, InfoWindow } from 'react-google-maps'
import { graphql } from "gatsby"

export const query = graphql`
{
    allContentfulLocations {
      nodes {
        id
        name
        location {
          lat
          lon
        }
      }
    }
  }
`

const Map = ({props, data}) => {

      const {
              allContentfulLocations: { nodes: locations },
            } = data

    const [infoWindow, setInfoWindow] = useState(false)

    return (

        <GoogleMap
            defaultZoom={12}
            defaultCenter={{
                lat: location.location.lat
                lng: location.location.lon
            }}
            >

            {locations.map(location => {
                return (
            <Marker
                onMouseOver={() => {
                    setInfoWindow(true)
                }}
                onClick={() => props.setmodal(true)}
                position={{
                    lat: 34.0522,
                    lng: 118.2437
                }}
                />
                )
              })}

        </GoogleMap>
    )
}

export default Map;


Solution

  • Use:

    import React from 'react'
    import { GoogleMap, Marker, InfoWindow } from 'react-google-maps'
    import { useStaticQuery, graphql } from "gatsby"
    
    
    const Map = (props) => {
      const data = useStaticQuery(graphql`
    {
        allContentfulLocations {
          nodes {
            id
            name
            location {
              lat
              lon
            }
          }
        }
      }
    `)
          const {
                  allContentfulLocations: { nodes: locations },
                } = data
    
        const [infoWindow, setInfoWindow] = useState(false)
    
        return (
    
            <GoogleMap
                defaultZoom={12}
                defaultCenter={{
                    lat: location.location.lat
                    lng: location.location.lon
                }}
                >
    
                {locations.map(({location}) => {
                    console.log(location);
                    return (
                <Marker
                    onMouseOver={() => {
                        setInfoWindow(true)
                    }}
                    onClick={() => props.setmodal(true)}
                    position={{
                        lat: 34.0522,
                        lng: 118.2437
                    }}
                    />
                    )
                  })}
    
            </GoogleMap>
        )
    }
    
    export default Map;
    

    If your component (Map) is not a page, you won't be able to use page queries and therefore you will be forced to use a static query

    Notice the destructuring in the map loop:

    locations.map(({location}) =>
    

    In the way you were using the loop, location was the iterable variable, not the location object itself. You should access to location.location in your approach, you're avoiding that repetition, using a destructuring in the same declaration on the iterable object as I provided. I've also added a console.log() for debugging purposes, take a look at what's inside in both approaches.

    In addition, if you look at your code:

    const Map = ({props, data}) => {
    

    You are destructuring props as props itself so. I've removed that destructuring and I've added it to:

      const {
              allContentfulLocations: { nodes: locations },
            } = props.data