简体   繁体   中英

Gatsby/Contentful Pass data from one component to another

I'm playing around with Gatsby, Contentful and Google Maps. Here's the page that I'm working on:

import React, { useState } from 'react'
import Layout from '../components/Layout'
import { withGoogleMap, withScriptjs } from 'react-google-maps'
import Map from '../components/Map'
import 'react-responsive-modal/styles.css';
import { Modal } from 'react-responsive-modal';

const MapComponent = withScriptjs(withGoogleMap(Map));

export default function IndexPage() {

    const [modal, setmodal] = useState(false)

    return (
        <Layout>
            <div style={{ width: "100%", height: "100vh" }} >

                <MapComponent
                    googleMapURL={`https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places&key=${"AIzaSyAGJcMjH34D2QWQpOKhOulJGfZ9kXVQuj8"}`}
                    loadingElement={<div style={{ height: `100%` }} />}
                    containerElement={<div style={{ height: `100%` }} />}
                    mapElement={<div style={{ height: `100%` }} />}
                    setmodal={setmodal}
                />
            </div>

            <Modal
                open={modal}
                onClose={() => setmodal(false)}
            >
                <h1>Contentful Content Here</h1>
            </Modal>

        </Layout>
    )
}

I extended the page and created a./components/Map component to it. In the Map component I'm querying Contentful data.

Like this:

import React, { useState } 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(null)

    return (
        <GoogleMap
            defaultZoom={12}
            defaultCenter={{
                lat: 14.05223,
                lng: 218.2437
            }}
        >

            {locations.map(({ location }) => {
                console.log(location);
                return (
                    <Marker
                        onMouseOver={() => {
                            setInfoWindow(true)
                        }}
                        onClick={() => {
                            props.setmodal(true)
                        }}
                        position={{
                            lat: location.lat,
                            lng: location.lon
                        }}
                    />
                )
            })}
        </GoogleMap>
    )
}

export default Map;

Now, I want to use the Contentful data inside the component on my page too. How can I access the Contentful data from the component and implement it on my page?

My Approach was to use useState with data,setData like this on my page:

import React, { useState } from 'react'
import Layout from '../components/Layout'
import { withGoogleMap, withScriptjs } from 'react-google-maps'
import Map from '../components/Map'
import 'react-responsive-modal/styles.css';
import { Modal } from 'react-responsive-modal';

const MapComponent = withScriptjs(withGoogleMap(Map));

export default function IndexPage() {

    const [modal, setmodal] = useState(false)
    const [data, setData] = (null)

    return (
        <Layout>
            <div style={{ width: "100%", height: "100vh" }} >

                <MapComponent
                    googleMapURL={`https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places&key=${"AIzaSyAGJcMjH34D2QWQpOKhOulJGfZ9kXVQuj8"}`}
                    loadingElement={<div style={{ height: `100%` }} />}
                    containerElement={<div style={{ height: `100%` }} />}
                    mapElement={<div style={{ height: `100%` }} />}
                    setmodal={setmodal}
                    setData={setData}
                />
            </div>

            <Modal
                open={modal}
                onClose={() => setmodal(false)}
            >
                <h1>{data.locations.name}</h1>
            </Modal>

        </Layout>
    )
}

And in the Map component, inside the Marker component I've added a props.setData for the to access the data.

import React, { useState } 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(null)

    return (
        <GoogleMap
            defaultZoom={12}
            defaultCenter={{
                lat: 14.05223,
                lng: 218.2437
            }}
        >

            {locations.map(({ location }) => {
                console.log(location);
                return (
                    <Marker
                        onMouseOver={() => {
                            setInfoWindow(true)
                        }}
                        onClick={() => {
                            props.setmodal(true)
                            props.setData(location)
                        }}
                        position={{
                            lat: location.lat,
                            lng: location.lon
                        }}
                    />
                )
            })}
        </GoogleMap>
    )
}

export default Map;

I'm stuck now. Getting an error saying that allContentfulLocations is undefined and I'm not receiving the data into my page. Can someone help me to get it right?

In your IndexPage , your state is held by data , not by setData . setData is just a setter function that sets the state within the provided data but your information is inside data , in addition, the setter doesn't accept any parameter by default so won't be able to use props.setData(location) . Change it to:

import React, { useState } from 'react'
import Layout from '../components/Layout'
import { withGoogleMap, withScriptjs } from 'react-google-maps'
import Map from '../components/Map'
import 'react-responsive-modal/styles.css';
import { Modal } from 'react-responsive-modal';

const MapComponent = withScriptjs(withGoogleMap(Map));

export default function IndexPage() {

    const [modal, setmodal] = useState(false)
    const [data, setData] = useState(null)

    const setYourData= data => setData(data);

    return (
        <Layout>
            <div style={{ width: "100%", height: "100vh" }} >

                <MapComponent
                    googleMapURL={`https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places&key=${"AIzaSyAGJcMjH34D2QWQpOKhOulJGfZ9kXVQuj8"}`}
                    loadingElement={<div style={{ height: `100%` }} />}
                    containerElement={<div style={{ height: `100%` }} />}
                    mapElement={<div style={{ height: `100%` }} />}
                    setmodal={setmodal}
                    setYourData={setYourData}
                    data={data}
                />
            </div>

            <Modal
                open={modal}
                onClose={() => setmodal(false)}
            >
                { data && <h1>{data.location.name}</h1>}
            </Modal>

        </Layout>
    )
}

Now, you are passing a function ( setYourData ) that is accepting a parameter ( data ) and sets the state accordingly, so your props.setData(location). Will become:

props.setYourData(location);

This value needs to be passed again downwards to your map component using data={data} (I would strongly suggest a new naming since it's a bit repetitive and may lead to some misunderstandings).

Note also the { data && <h1>{data.locations.name}</h1>} control. Initially, you've set to null the state, so your code can't reach data.locations .

Once the data is passed to the map component, you can play whatever you want with now new brand location , stored in data ( props.data ). Your map component should look like this:

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

const Map = (props) => {
 console.log(props.data) // here you have your new data/location
    const data = useStaticQuery(graphql`
{
    allContentfulLocations {
      nodes {
        id
        name
        location {
          lat
          lon
        }
      }
    }
  }
`)
    const {
        allContentfulLocations: { nodes: locations },
    } = data

    const [infoWindow, setInfoWindow] = useState(null)

    return (
        <GoogleMap
            defaultZoom={12}
            defaultCenter={{
                lat: 14.05223,
                lng: 218.2437
            }}
        >

            {locations.map(({ location }) => {
                console.log(location);
                return (
                    <Marker
                        onMouseOver={() => {
                            setInfoWindow(true)
                        }}
                        onClick={() => {
                            props.setmodal(true)
                            props.setYourData(location)
                        }}
                        position={{
                            lat: location.lat,
                            lng: location.lon
                        }}
                    />
                )
            })}
        </GoogleMap>
    )
}

export default Map;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM