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

#javascript #reactjs #react-props #react-state #react-state-management

#javascript #reactjs #react-props #реагировать-состояние #реагирование на управление состоянием

Вопрос:

Я пишу приложение для прогноза погоды с помощью React. Я извлекаю данные из openweathermap.org API. Но чтобы использовать это, мне нужно знать местоположение пользователя. Поэтому я также последовательно использую другие API для определения IP-адреса пользователя, местоположения, а затем погодных данных в соответствии с этим местоположением. При каждом состоянии выборки я обновляю начальные состояния с помощью извлеченной информации. Например, когда я извлекаю Ip, я обновляю userIp в состояниях с помощью setState, затем, когда извлекаются широта и долгота, я также обновляю userLat и userLng. Таким образом, WeatherData в состояниях, который изначально является пустым массивом, обновляется последним. Проблема в том, что рендеринг запускается каждый раз, когда изменяется одно из состояний. Поскольку один из дочерних компонентов, которому я передаю WeatherData в качестве реквизита, использует объект в этом выбранном массиве WeatherData, я получаю сообщение об ошибке, потому что до обновления WeatherData выполняется рендеринг и передает пустой массив этому компоненту. Я попытался использовать оператор 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_SECRETAPIKEYamp;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}amp;lon=${this.state.userLng}amp;units=metricamp;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;
  

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

1. Обычно в этом случае я бы обновил дочерний компонент, чтобы вернуть значение null, если необходимый реквизит не определен.

Ответ №1:

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

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

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

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

 > true amp;amp; 123
< 123
> false amp;amp; 123
< false
  

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

1. Эй, спасибо за идею. Я изменил начальное состояние с массива на объект, но, основываясь на вашем ответе, добавил еще один оператор if в рендеринг, и это сработало.