Использование Promise.all для размещения маркеров на Google Картах - объекты недопустимы в качестве дочерних элементов React (найдено: [Promise объекта]) - PullRequest
0 голосов
/ 24 июня 2018

Я уже несколько дней пытаюсь разместить маркеры по координатам на Картах Google, но сталкиваюсь с этой ошибкой:

Объекты недопустимы в качестве дочерних элементов React (найдено: [обещание объекта])

Итак, я обнаружил, что могу использовать Promise.all для решения этой проблемы, но у меня возникают проблемы при правильном выполнении этого. Я не совсем уверен, как и где в моем компоненте я должен это делать.

Кто-нибудь может мне помочь?

Вот код:

import React, { Component } from "react";
import { Map, InfoWindow, Marker, GoogleApiWrapper } from "google-maps-react";
import Navbar from "./Navbar";
import { connect } from "react-redux";
import { getVacations } from "./redux";
import Geocode from "react-geocode";

class GoogleMaps extends Component {
  constructor() {
    super();
    this.state = {
      coords: []
    }
  }

  componentDidMount = () => {
    this.props.getVacations();
  }

  render() {
    console.log(this.props);

    const coordinates = this.props.vacations.map(coordinate => {
      const convert = Geocode.fromAddress(coordinate.location);
      return convert;
    })

    Promise.all(coordinates).then(locations => {
      const markers = locations.map(place => {
        console.log(place);
        const lat = place.results[0].geometry.location.lat;
        const lng = place.results[0].geometry.location.lng;
        return [
          <Marker
            key={place._id}
            position={
              {
                lat: lat, 
                lng:lng
              }
            }
            animation={2}
          />
        ]
      })
      this.setState({
        coords: markers
      })
    })

    return (
      <div>
        <Navbar />
        <Map
          google={this.props.google}
          zoom={4} 
        >
          {this.state.coords}
        </Map>
      </div>
    )
  }
}

const connectVaca = connect(state => ({vacations: state}), {getVacations})(GoogleMaps);

export default GoogleApiWrapper({
            apiKey: "API KEY HERE"
})(connectVaca)

Вот мое действие getVacations и редуктор:

export const getVacations = () => {
    return dispatch => {
        axios.get("/vacations").then(response => {
            dispatch({
                type: "GET_VACATIONS",
                vacations: response.data
            })
        }).catch(err => {
            console.log(err);
        })
    }
}

const reducer = (state = [], action) => {
    switch(action.type){
        case "GET_VACATIONS":
            return action.vacations;
        default:
            return state;
    }
}

1 Ответ

0 голосов
/ 24 июня 2018

Вы не должны иметь асинхронных вызовов функций в вашем методе рендеринга.Наилучшим местом для асинхронных вызовов является componentDidMount согласно документации реагирования.

Поместите ваш вызов Promise.all в функцию componentDidMount.Всякий раз, когда ваш компонент монтируется, эта функция будет выполняться.Затем, всякий раз, когда setState вызывается для установки coords, ваш компонент будет перерисовываться с обновленными значениями coords.

import React, { Component } from "react";
import { Map, InfoWindow, Marker, GoogleApiWrapper } from "google-maps-react";
import Navbar from "./Navbar";
import { connect } from "react-redux";
import { getVacations } from "./redux";
import Geocode from "react-geocode";

class GoogleMaps extends Component {
  constructor() {
    super();
    this.state = {
      coords: []
    }
  }

  componentDidMount = () => {
    this.props.getVacations();
    const coordinates = this.props.vacations.map(coordinate => {
      const convert = Geocode.fromAddress(coordinate.location);
      return convert;
    })
    Promise.all(coordinates).then(locations => {
      const markers = locations.map(place => {
        console.log(place);
        const lat = place.results[0].geometry.location.lat;
        const lng = place.results[0].geometry.location.lng;
        return (
          <Marker
            key={place._id}
            position={
              {
                lat: lat, 
                lng:lng
              }
            }
            animation={2}
          />
        )
      })
      this.setState({
        coords: markers
      })
    })
  }

  render() {
    return (
      <div>
        <Navbar />
        <Map
          google={this.props.google}
          zoom={4} 
        >
          {this.state.coords}
        </Map>
      </div>
    )
  }
}

const connectVaca = connect(state => ({vacations: state}), {getVacations})(GoogleMaps);

export default GoogleApiWrapper({
            apiKey: "API KEY HERE"
})(connectVaca)

Редактировать: Поскольку loadVacations является thunk, вам нужно передать его dispatch.Измените вашу mapDispatchToProps переданную функцию на connect следующим образом:

const connectVaca = connect(
  state => ({vacations: state}),
  dispatch => {
    return { getVacations: () => dispatch(getVacations()) }
  }
)(GoogleMaps);

Edit2: Это связано с тем фактом, что реакция запускает начальный render() вызов сразу после перехода на страницу.загружен.Затем, как только ваш компонент смонтирован, вызывается componentDidMountcomponentDidMount вы запускаете асинхронную функцию getVacations.Поскольку вы не ожидаете завершения вызова API в getVacations, создание маркера происходит без загрузки отпуска.Всякий раз, когда вы посещаете новую вкладку и возвращаетесь к своему приложению, render происходит снова с загруженными отпусками от предыдущего вызова API, поэтому они появляются.

Попробуйте вернуть обещание из вашего действия getVacations.Затем, всякий раз, когда вы звоните getVacations в componentDidMount, соедините then вызов getVacations.Внутри then находится место, где вы должны разместить свои координаты создания + Promise.all вызова.Тогда я верю, что ваш код будет работать.

export const getVacations = () => {
    return dispatch => {
        // returning axios.get will return a promise you can chain a then call on
        return axios.get("/vacations").then(response => {
            dispatch({
                type: "GET_VACATIONS",
                vacations: response.data
            })
        }).catch(err => {
            console.log(err);
        })
    }
}

Тогда в вашей функции componentDidMount:

componentDidMount = () => {
    this.props.getVacations().then(() => {
       // Place coordinates, your Promise.all call, and your setState call here 
    });
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...