Как остановить передачу элемента состояния дочернему компоненту до его установки?

Я пишу приложение с прогнозом погоды на React. Я получаю данные из API openweathermap.org. Но чтобы использовать это, мне нужно знать местонахождение пользователя. Поэтому я последовательно использую другие API, чтобы идентифицировать IP-адрес пользователя, местоположение, а затем данные о погоде в соответствии с этим местоположением. В каждом состоянии выборки я обновляю начальные состояния с полученной информацией. Например, когда я получаю Ip, я обновляю userIP в состояниях с помощью setState, затем, когда выбираются широта и долгота, я также обновляю userLat и userLng. Таким образом, weatherData в состояниях, который изначально является пустым массивом, обновляется последним. Проблема в том, что рендеринг запускается каждый раз при изменении одного из состояний. Поскольку один из дочерних компонентов, которому я передаю weatherData в качестве свойств, использует объект в этом извлеченном массиве weatherData, я получаю сообщение об ошибке, потому что до тех пор, пока weatherData не будет обновлена, render выполняется и передает пустой массив этому компоненту. Я попытался использовать оператор if, чтобы проверить, является ли weatherData пустым массивом, прежде чем возвращать результаты, но почему-то это не работает.

Вот мой файл App.js:

import React, {Component} from 'react';
import './App.css';
import Mainblock from './Mainblock';
import Hourly from './Hourly';
import Weekly from './Weekly';

class App extends Component {
  constructor() {
    super()

    this.state = {
      userIp: 0,
      cityName: '',
      cityNameNoSpace: '',
      userLat: 0,
      userLng: 0
    }

  }
  

  componentDidMount(){

    fetch("https://geoip-db.com/json/").then((data)=> {

      return data.json();
    }).then((ip)=>{

      this.setState({userIp: ip.IPv4});
      this.locateClient(this.state.userIp);
    });
  }

  locateClient = (clientIp) => {
    fetch(`https://ip-geolocation.whoisxmlapi.com/api/v1?apiKey=at_SECRETAPIKEY&ipAddress=${clientIp}`).then((data)=>{

      return data.json();
    }).then((locationInfo)=>{

      this.setState({userLat: locationInfo.location.lat, userLng: locationInfo.location.lng, cityName: locationInfo.location.city});

      let cityArray = Array.from(locationInfo.location.city);

      let cityNameFiltered = '';
      
      cityArray.forEach((letter)=>{
        cityNameFiltered = cityNameFiltered + letter;
        return cityNameFiltered;
      })

      this.setState({cityNameNoSpace: cityNameFiltered});

      this.getWeatherData(this.state.cityNameNoSpace);

    });
  }

  getWeatherData = (userCity) => {

    fetch(`https://api.openweathermap.org/data/2.5/onecall?lat=${this.state.userLat}&lon=${this.state.userLng}&units=metric&appid=SECRETAPIKEY`).then((data)=>{

      return data.json();
    }).then((weatherInfo)=>{

      this.setState({weatherData: weatherInfo});
    });
  }

  

  render() {

    return (
      <div className="whole-container">
        <div className="lside">
          <Mainblock states={this.state}/>
          <Weekly />
        </div> 
        <Hourly />
      </div>
    );
    
  }
}

export default App;

person Noiseymur    schedule 16.09.2020    source источник
comment
Обычно в этом случае я обновляю дочерний компонент, чтобы он возвращал ноль, если необходимая опора не определена.   -  person Charlie Stanard    schedule 16.09.2020


Ответы (1)


Поскольку ваш компонент Mainblock ожидает, что опора состояний будет объектом со свойством weatherData, где weatherData должна быть массивом, вы можете условно отобразить компонент.

Для условного рендеринга это будет выглядеть следующим образом:

render() {
    return (
      <div className="whole-container">
        <div className="lside">
          {Array.isArray(this.state.weatherData) && <Mainblock states={this.state}/> }
          <Weekly />
        </div> 
        <Hourly />
      </div>
    );
  }

Причина, по которой это работает, заключается в том, что javascript оценивает логические выражения и возвращает правую часть выражения, когда оно истинно, в противном случае возвращает ложь.

> true && 123
< 123
> false && 123
< false
person kyle    schedule 16.09.2020
comment
Эй, спасибо за идею. Я изменил начальное состояние с массива на объект, но, основываясь на вашем ответе, добавил к рендерингу еще один оператор if, и он сработал. - person Noiseymur; 17.09.2020