尝试针对使用 OpenWeatherMaps API 的城市的无效提取生成警报

Trying to generate alerts for invalid fetches for cities with OpenWeatherMaps API

所以我正在尝试为试图通过 OpenWeatherMaps 访问无效城市的天气数据的用户生成警报 API。

我大部分时间都在那里。然而,当我对此进行测试时,发生了两件事:

  1. 浏览器生成正确的警报。

但是,一旦您单击警报的确认按钮...

  1. “未处理的拒绝(TypeError):无法解构‘(中间值)’的 属性 'data',因为它未定义。”

这是我目前使用的代码:

const fetchWeather = async (query) => {
  const { data } = await axios.get(
    URL,
    {
      params: {
        q: query,
        units: "metric",
        APPID: API_KEY,
      },
    }).catch (function (error) {
      alert(error.response.data.message)
    })
};

完整代码:

Search.jsx 分量:

import React, { useState } from "react";
import fetchWeather from "../api/fetchWeather";
import { makeStyles } from "@material-ui/core/styles";
import TextField from "@material-ui/core/TextField";
import InputAdornment from '@material-ui/core/InputAdornment';
import SearchIcon from '@material-ui/icons/Search';

const Search = () => {
  let [displayResults, setDisplayResults] = useState(false);
  let [query, setQuery] = useState("");
  let [feelsLike, setFeelsLike] = useState(0);
  let [mainTemp, setMainTemp] = useState(0);
  let [description, setDescription] = useState("");
  let [main, setMain] = useState("");
  let [iconID, setIconID] = useState("");
  let [windSpeed, setWindSpeed] = useState("");
  let [windGust, setWindGust] = useState("");
  let [windDirection, setWindDirection] = useState("");
  let [name, setName] = useState("");
  let [country, setCountry] = useState("");

  const useStyles = makeStyles((theme) => ({
    button: {
      backgroundColor: "#FDB124",
      color: "black",
      fontFamily: "Mortal Kombat",
      "&:hover": {
        background: "#B57602",
      },
    },
    root: {
      "& > *": {
        display: 'flex',
        margin: theme.spacing(1),
        // width: "25ch",
      },
      input: {
        color: "white",
      },
      primary: {
        backgroundColor: "#FDB124",
      },
      "& label.Mui-focused": {
        color: "#FDB124",
      },
      "& label": {
        color: "#FDB124",
        fontFamily: "Mortal Kombat",
      },
      "& input": {
        color: "#FDB124",
        fontFamily: "Mortal Kombat",
      },
      "& .MuiInput-underline:after": {
        borderBottomColor: "#FDB124",
      },
      "& .MuiOutlinedInput-root": {
        "& fieldset": {
          borderColor: "#FDB124",
        },
        "&:hover fieldset": {
          borderColor: "#FDB124",
        },
        "&.Mui-focused fieldset": {
          borderColor: "#FDB124",
        },
      },
    },
  }));

  const weatherSearch = async (e) => {
    if (e.key === "Enter") {
      const data = await fetchWeather(query);
      setDisplayResults(true);
      setFeelsLike(data.main.feels_like);
      setMainTemp(data.main.temp);
      setDescription(data.weather[0].description);
      setMain(data.weather[0].main);
      setIconID(data.weather[0].icon);
      setWindSpeed(data.wind.speed);
      setWindGust(data.wind.gust);
      setWindDirection(data.wind.deg);
      setName(data.name);
      setCountry(data.sys.country);
      setQuery("");
    }
  };

  const classes = useStyles();

  return (
    <div>
      <h1 className="cityChoose">CHOOSE YOUR CITY:</h1>
      
      <TextField
        id="outlined-basic"
        label="Enter City"
        variant="outlined"
        color="secondary"
        size="small"
        spellCheck="false"
        className={classes.root}
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        onKeyPress={weatherSearch}
        InputProps={{
          startAdornment: (
            <InputAdornment position="start" style={{color: "#FDB124"}}>
              <SearchIcon />
            </InputAdornment>
          ),
        }}
      />
      
      {displayResults ? null : <h4>Example: Chicago, IL, US</h4>}
      
      {displayResults ? (
        <>
          <h1>The current weather in {name}, {country} is:</h1>

          <span>
            <div>
              {description}
              <br />
              <img
                src={"http://openweathermap.org/img/wn/" + iconID + "@2x.png"}
              />
            </div>
            <h2>Temperature:</h2>
            <br />
            <div>
              {(mainTemp * 1.8 + 32).toFixed(1)} &deg;F / {mainTemp.toFixed(1)}{" "}
              &deg;C
            </div>
            <br />
            <br />
            <h2>Winds:</h2>
            <div>Wind Direction: {windDirection}</div>
            <div>Wind Speed: {windSpeed} MPH</div>
            <div>Wind Gusts: {windGust} MPH</div>
          </span>
        </>
      ) : null}
    </div>
  );
};

export default Search;

fetchWeather.jsx:

import React from "react";
import axios from "axios";

const URL = "https://api.openweathermap.org/data/2.5/weather";
const API_KEY = "*key is here*";

const fetchWeather = async (query) => {
  const { data } = await axios.get(
    URL,
    {
      params: {
        q: query,
        units: "metric",
        APPID: API_KEY,
      },
    }).catch (function (error) {
      if (error.response) {
        console.log(error.response.data);
        console.log(error.response.status);
        console.log(error.response.headers);
      } else if (error.request) {
        console.log(error.request);
      } else {
        console.log("Error: ", error.message);
      }
    });

  console.log(data);
  return data;
};

export default fetchWeather;

尝试像这样检查错误:

        if (error.response) {
          console.log(error.response.data);
          console.log(error.response.status);
          console.log(error.response.headers);
        } else if (error.request) {
          console.log(error.request);
        } else {
          console.log("Error", error.message);
        }

工作样本:https://codesandbox.io/s/openweathermap-test-forked-35781?file=/src/index.js:434-749

好的,所以您遇到的问题与 axios 抛出错误并且不会 return 具有键 data 的对象返回 const { data } = await axios.get( 这一事实有关。解决这个问题非常简单。

它无法从你错误的 axios 调用中解构 data 的原因是你没有在 catch 块中容纳它

.catch (function (error) {
      alert(error.response.data.message)
    })

您的 catch 块应该如下所示:

.catch (error => {
                return {data: error.response.data ? error.response.data : 'No data'}
            }
        )

所以您的 fetchWeather 函数的最终(和工作)版本是...

const fetchWeather = async (query) => {
    const { data } = await axios.get(
        'https://httpstat.us/400',
        {
            params: {
                q: query,
                units: "metric",
                APPID: 'XXXXXXXX',
            },
        })
        .catch (error => {
                return {data: error.response.data ? error.response.data : 'No data'}
            }
        )
    console.log(data)
};

您可以尝试使用这两个测试网址:

https://httpstat.us/200 returns 200 OK
https://httpstat.us/400 returns 400 Bad Request

后者会触发catch


请记住,如果您调用的域未解析为 ip(例如 http://hskjfhshgsg.com/api/sss/sss 或类似内容),我编写的代码将抛出错误.)