LoginSignup
gallantsummerwind
@gallantsummerwind

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

ReactのOpenWeatherの表示方法について

Q&AClosed

Open Weather APIを表示させたい。

ReactでOpen Weather APIを利用して表示させるWebアプリを作成しているのですが、以下のコードではうまく表示できないため、解決方法を教えて下さい。

APIからJSON文字列の取得はできており、検証モードでも確認できました。

エラーコードは以下の通りです。

data is not defined ReferenceError: data is not defined at Show

Reactのコードは以下の通り。

import React, { useEffect, useState } from 'react'

export const Show = () => {
  const url = `https://api.openweathermap.org/data/2.5/weather?id=${City}&appid=${API_key}`
  const [loading, setLoading] = useState(true)

  useEffect(() => {
    const weatherData = async () => {
      let res = await getWeatherData(url);
      setLoading(false)
      console.log(res)
    }
    weatherData()
  }, [])

  const getWeatherData = () => {
    return new Promise((resolve, reject) => {
      fetch(url)
        .then((response) => response.json())
        .then((data) => resolve(data))
    })
  }

  return (
    <>
      {loading ? (
        <h1>ロード中</h1>
      ) : <>
        <h1>データ取得済</h1>
        <section>
          <div class="location">東京</div>
          {/* <div class="temp"><p>{data.main.temp}°F</p></div> */}
          {/* <div class="description">{res.weather ? <p>{res.weather[0].main}</p>: null}</div> */}
          {/* <div class="windSpeed">{res.wind ? <p>{res.wind.speed} HMP</p> : null}</div> */}
          {/* <div class="windDeg">{res.wind ? <p>{res.wind.deg}</p> : null}</div> */}
          {/* <div class="windGust">{res.wind ? <p>{res.wind.gust}</p> : null}</div> */}
        </section>
      </>
      }
    </>
  )
}

取得してきたJOSN文字列は以下の通りとなります。

###要求後の応答内容となります。

{
    "coord": {
        "lon": 31.2007,
        "lat": 30.3539
    },
    "weather": [
        {
            "id": 800,
            "main": "Clear",
            "description": "clear sky",
            "icon": "01d"
        }
    ],
    "base": "stations",
    "main": {
        "temp": 295.09,
        "feels_like": 295.22,
        "temp_min": 295.09,
        "temp_max": 295.6,
        "pressure": 1016,
        "humidity": 72,
        "sea_level": 1016,
        "grnd_level": 1014
    },
    "visibility": 10000,
    "wind": {
        "speed": 2.73,
        "deg": 263,
        "gust": 4.15
    },
    "clouds": {
        "all": 0
    },
    "dt": 1699942690,
    "sys": {
        "type": 2,
        "id": 47682,
        "country": "EG",
        "sunrise": 1699935583,
        "sunset": 1699973975
    },
    "timezone": 7200,
    "id": 347236,
    "name": "Toukh",
    "cod": 200
}

表示させたい部分はコメントアウトの部分となります。

<div class="temp"><p>{data.main.temp}°F</p></div>
0

2Answer

APIからJsonファイルの取得はできており

ファイルではなく、fetch(url) で指定の url に要求をかけると応答として JSON 文字列が返ってくるのですよね。サンプルでいいのでその JSON 文字列を質問欄に追記してください。


【追記】

普通に、昔ながらのやり方で state を使ってはいかがですか?

以下は Visual Studio 2022 のテンプレートで作った React + Web API アプリの実行結果ですが、これがどのように state を使っているか説明します。

react.jpg

コードは以下の通りです。

import React, { Component } from 'react';

export class FetchData extends Component {
    static displayName = FetchData.name;

    constructor(props) {
        super(props);
        this.state = { forecasts: [], loading: true };
    }

    componentDidMount() {
        this.populateWeatherData();
    }

    static renderForecastsTable(forecasts) {
        return (
            <table className="table table-striped" aria-labelledby="tableLabel">
                <thead>
                    <tr>
                        <th>Date</th>
                        <th>Temp. (C)</th>
                        <th>Temp. (F)</th>
                        <th>Summary</th>
                    </tr>
                </thead>
                <tbody>
                    {forecasts.map(forecast =>
                        <tr key={forecast.date}>
                            <td>{forecast.date}</td>
                            <td>{forecast.temperatureC}</td>
                            <td>{forecast.temperatureF}</td>
                            <td>{forecast.summary}</td>
                        </tr>
                    )}
                </tbody>
            </table>
        );
    }

    render() {
        let contents = this.state.loading
            ? <p><em>Loading...</em></p>
            : FetchData.renderForecastsTable(this.state.forecasts);

        return (
            <div>
                <h1 id="tableLabel">Weather forecast</h1>
                <p>This component demonstrates fetching data from the server.</p>
                {contents}
            </div>
        );
    }

    async populateWeatherData() {
        const response = await fetch('weatherforecast');
        const data = await response.json();
        this.setState({ forecasts: data, loading: false });
    }
}

コードの下の方にある fetch('weatherforecast') で Web API を呼び出すと、以下の JSON 文字列が返ってきます。

[
  {"date":"2023-11-15","temperatureC":14,"temperatureF":57,"summary":"Bracing"},
  {"date":"2023-11-16","temperatureC":21,"temperatureF":69,"summary":"Warm"},
  {"date":"2023-11-17","temperatureC":47,"temperatureF":116,"summary":"Warm"},
  {"date":"2023-11-18","temperatureC":0,"temperatureF":32,"summary":"Hot"},
  {"date":"2023-11-19","temperatureC":34,"temperatureF":93,"summary":"Hot"}
]

その下の const data = await response.json(); で data には JSON 文字列をデシリアライズしたJavaScript オブジェクト(連想配列)が代入されます。

それを setState で state に設定すると自動的に再度 render が動いて上の画像のように結果が表示されます。

2Like

以下のとおり、useStateを追加して表示することができました。
内容については、もう少し勉強が必要と感じました。

      let temp = Math.round(res.main.temp)

      const weather = {
        temp: `${temp}`
      }
      setWeather(weather)

import React, { useEffect, useState } from 'react'
// import OpenWeather from "Weather-API-search"

export const Show = () => {

  const url = `https://api.openweathermap.org/data/2.5/weather?id=${City}&appid=${API_key}`
  const [loading, setLoading] = useState(true)
  const [weather, setWeather] = useState("")
  // const [location, setLocation] = useState("")

  useEffect(() => {
    const weatherData = async () => {
      let res = await getWeatherData(url);
      setLoading(false)
      console.log(res)

      let temp = Math.round(res.main.temp)

      const weather = {
        temp: `${temp}`
      }
      setWeather(weather)

    }
    weatherData()
  }, [])

  const getWeatherData = () => {
    return new Promise((resolve, reject) => {
      fetch(url)
        .then((response) => response.json())
        .then((data) => resolve(data))
    })
  }

  return (
    <>
      {loading ? (
        <h1>ロード中</h1>
      ) : <>
        <h1>データ取得済</h1>
        <section>
          <div class="location">東京</div>
          <div class="temp"><p>{weather.temp}°F</p></div>
          {/* <div class="description">{res.weather ? <p>{res.weather[0].main}</p>: null}</div> */}
          {/* <div class="windSpeed">{res.wind ? <p>{res.wind.speed} HMP</p> : null}</div> */}
          {/* <div class="windDeg">{res.wind ? <p>{res.wind.deg}</p> : null}</div> */}
          {/* <div class="windGust">{res.wind ? <p>{res.wind.gust}</p> : null}</div> */}
        </section>
      </>
      }
    </>
  )
}
0Like

Your answer might help someone💌