Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
229 views
in Technique[技术] by (71.8m points)

javascript - 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?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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;

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
...