Почему не выводятся данные из fetch запроса в элементы на React?

Рейтинг: 0Ответов: 1Опубликовано: 10.03.2023

class MyWeather extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            data: {}
        };
    }

    componentDidMount() {
        fetch('https://api.openweathermap.org/data/2.5/weather?q=ODESA&units=metric&APPID=5d066958a60d315387d9492393935c19')
            .then(response => response.json())
            .then(data => this.setState({ data }));
        console.log(this.state.data);
    }


    render() {
        const { data } = this.state;
        const srcURL = `https://openweathermap.org/img/w/${data.weather[0]['icon']}.png`;
        return (
            <div>
                <h1>City: {data.name}</h1>
                <p>Temperature: {Math.round(data.main.temp)}&deg;C</p>
                <p>Pressure: {data.main.pressure} hPa</p>
                <p>Description: {data.weather[0]['description']}</p>
                <p>Humidity: {data.main.humidity}%</p>
                <p>Speed: {data.wind.speed}m/s</p>
                <p>Degree: {data.wind.deg}&deg;</p>
                <img src={srcURL} alt='Weather' title='Weather'/>
            </div>
        );
    }
}

ReactDOM.render(
  <MyWeather />,
  document.body
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

В консоли есть ошибка:

TypeError: Cannot read properties of undefined (reading '0')

введите сюда описание изображения введите сюда описание изображения

Ответы

▲ 1Принят

Ошибка вызвана тем, что при первом рендериге не проверяются значения на их существование.

Необходимо в render добавить проверку, что в this.state.data есть данные.

Допустим, в качестве примера, проверить, что в data есть ключ name:

render() {

  const { data } = this.state;
  if (data.name) {
    const srcURL = `https://openweathermap.org/img/w/${data.weather[0]['icon']}.png`;
    return (
      <div>
        <h1>City: {data.name}</h1>
        <p>Temperature: {Math.round(data.main.temp)}&deg;C</p>
        <p>Pressure: {data.main.pressure} hPa</p>
        <p>Description: {data.weather[0]['description']}</p>
        <p>Humidity: {data.main.humidity}%</p>
        <p>Speed: {data.wind.speed}m/s</p>
        <p>Degree: {data.wind.deg}&deg;</p>
        <img src={srcURL} alt='Weather' title='Weather'/>
      </div>
    );
  } else {
    return null; // Или что то другое, говорящее, что компонент ожидает данные
  }
}

В больших проектах, я бы рекоменовал избавляться в методе render от создания ненужных переменных и обращаться к this.state.data

Более красивый вариант:

render() {
  const {data} = this.state;
  if (!data.name) return null;
  const srcURL = `https://openweathermap.org/img/w/${data.weather[0]['icon']}.png`;
  return (
    <div>
      <h1>City: {data.name}</h1>
      <p>Temperature: {Math.round(data.main.temp)}&deg;C</p>
      <p>Pressure: {data.main.pressure} hPa</p>
      <p>Description: {data.weather[0]['description']}</p>
      <p>Humidity: {data.main.humidity}%</p>
      <p>Speed: {data.wind.speed}m/s</p>
      <p>Degree: {data.wind.deg}&deg;</p>
      <img src={srcURL} alt='Weather' title='Weather'/>
    </div>
  );
}