Gatsby / Contentful передает данные из одного компонента в другой

#javascript #reactjs #gatsby

#javascript #reactjs #gatsby

Вопрос:

Я играю с Gatsby, Contentful и Google Maps. Вот страница, над которой я работаю:

 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.expamp;libraries=geometry,drawing,placesamp;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>
    )
}

 

Я расширил страницу и создал для нее компонент ./components/Map . В компоненте Map я запрашиваю данные содержимого.

Вот так:

 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;
 

Теперь я хочу использовать данные содержимого внутри компонента и на своей странице. Как я могу получить доступ к содержательным данным из компонента и реализовать их на своей странице?

Мой подход заключался в использовании useState с данными, такими как setData на моей странице:

 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.expamp;libraries=geometry,drawing,placesamp;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>
    )
}

 

И в компоненте Map, внутри компонента Marker я добавил props.setData для доступа к данным.

 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;
 

Теперь я застрял. Получаю сообщение об ошибке, в котором говорится, что значение allContentfulLocations не определено, и я не получаю данные на свою страницу. Может кто-нибудь помочь мне сделать это правильно?

Ответ №1:

В вашем IndexPage случае ваше состояние удерживается data , а не by setData . setData это просто функция установки, которая устанавливает состояние в предоставленных данных, но ваша информация находится внутри data , кроме того, установщик не принимает никаких параметров по умолчанию, поэтому не сможет использовать props.setData(location) . Измените его на:

 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.expamp;libraries=geometry,drawing,placesamp;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 amp;amp; <h1>{data.location.name}</h1>}
            </Modal>

        </Layout>
    )
}
 

Теперь вы передаете функцию ( setYourData ), которая принимает параметр ( data ) и соответствующим образом устанавливает состояние, поэтому ваш props.setData(местоположение) . Станет:

 props.setYourData(location);
 

Это значение необходимо снова передать вашему компоненту карты, используя data={data} (я бы настоятельно рекомендовал новое название, поскольку оно немного повторяющееся и может привести к некоторым недоразумениям).

Обратите внимание также на { data amp;amp; <h1>{data.locations.name}</h1>} элемент управления. Изначально вы установили null состояние, поэтому ваш код не может достичь data.locations .

Как только data данные передаются компоненту map, вы можете воспроизводить все, что захотите, с новым брендом location , хранящимся в data ( props.data ) . Ваш компонент карты должен выглядеть следующим образом:

 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;
 

Комментарии:

1. Я пробовал это, но теперь получаю следующее сообщение об ошибке: TypeError: не удается прочитать свойство ‘0’ из null . Могу ли я запросить данные на странице, используя <h1>{data.location.name }</h1> ?

2. В IndexPage должен быть data.name directly ( console.log(data) ), чтобы знать, что внутри. Для доступа к lat и long , должно быть data.location.lat . Если вы хотите использовать его в компоненте map, то же самое с помощью префикса prop (т.е.: props.data.name , и т.д.)

3. Я реализовал это, но я все еще получаю одно и то же сообщение об ошибке, поступающее из IndexPage. Ошибка типа: не удается прочитать свойство ‘0’ из null

4. Добавьте элемент управления в <h1>{data.locations.name}</h1> . Поскольку вы пытаетесь получить доступ к нулевому свойству. Сделайте что-то вроде: {data amp;amp; <h1>{data.locations.name }</h1>}

5. Я пробовал это. К сожалению, я все еще получаю сообщение об ошибке. Должно быть что-то :/