如何设置状态元素,然后再将其传递给子组件?

时间:2020-09-16 20:53:53

标签: javascript reactjs react-props react-state react-state-management

我正在用React编写天气预报应用程序。我正在从openweathermap.org API中获取数据。但是要使用它,我需要知道用户的位置。因此,我也依次使用其他API来识别用户IP,位置,然后根据该位置识别天气数据。在每个获取状态下,我都会使用获取的信息来更新初始状态。例如,当我获取Ip时,我使用setState更新状态中的userIP,然后当获取纬度和经度时,也更新了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;

1 个答案:

答案 0 :(得分:0)

由于您的Mainblock组件期望状态props是一个具有weatherData属性的对象,其中weatherData应该是一个数组,因此您可以conditionally render该组件。

要有条件地进行渲染,如下所示:

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

之所以可行,是因为javascript计算布尔表达式并在为true时返回表达式的右侧,否则返回false。

> true && 123
< 123
> false && 123
< false