反应 - 试图从同一状态调用两个 Api?



所以我试图使用React创建一个足够简单的天气应用程序。我决定将有一个搜索框,用户在其中输入城市名称(使用onchange输入),当提交时,它将:

1:更改背景图像以显示UnSplash API中该城市的随机图像。(我先编码了这个,它工作得很好。)2. 它将在下面显示相关的天气细节,如温度,风速等。

function App() {
const [city, setCity] = useState("");

const fetchCityImage = (e) => {
e.preventDefault();
axios
.get(
`https://api.unsplash.com/photos/random?query=${city}&client_id={API_KEY}`
)
.then((response) => {
console.log(response.data);
setCity(response.data.urls.regular);
});
};

const fetchCityWeather = (e) => {
e.preventDefault();
axios
.get(
`https://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&appid=${OTHER_API_KEY}`
)
.then((response) => {
console.log(response.data);
});
};   
return (
<div className="App">
{/* HEADER */}
<div className="bg-black w-full h-[600px]">
<img
src={city}
alt="city image"
className="w-full h-[600px] object-cover"
/>
{/* Search and Info */}
<div className="absolute w-full h-[600px] top-[0%] flex flex-col justify-center bg-gradient-to-t from-black">
<div className="flex justify-center py-4">
<h1 className="font-bold">Weather App</h1>
</div>
<div className="flex justify-center">
<form
onSubmit={fetchCityWeather}
className="flex justify-between border border-white rounded-xl max-w-[300px] p-4"
>
<input
onChange={(e) => setCity(e.target.value)}
className="bg-transparent focus:outline-none placeholder:text-white"
type="text"
placeholder="Search a City..."
/>
<button onClick={fetchCityWeather}>
<BsSearch size={20} />
</button>
</form>
</div>
</div>
</div>
{/* DATA */}
</div>
);
}
export default App;

这就是我遇到问题的地方。我可以将天气数据记录到控制台,但是如何将API调用链接到相同的输入字段呢?或者相同的状态,甚至在页面的其余部分使用该数据?我一直在切换出onClick和onSubmit,以获得我想要的两个不同的结果,但需要它们在一起。

我希望我解释得足够好。谢谢。

要对两者使用相同的状态,您需要将city从字符串更改为对象。City应该是这样的:{ weather: 'sunny', img: 'cityImgSrc' }这样当你更新城市时你就可以更新你想要改变的属性使用它就像city.imgcity.weather一样简单

"link"API调用可以在控制台日志之后调用.then中的fetchCityImage。或者更好的方法可能是创建一个函数并使用async await,这样在获得所有数据后只更新一次状态。

我认为你应该尝试一种更像react的方法。以下是一些需要考虑的问题:

  • 在所需城市的名称之间创建一个明确的区分,现在一个适当的状态命名为city和你需要的数据到你的应用程序。你输入城市名称,当它改变时,应用程序去获取所需的数据。
  • 正如@Jawwaad Sabree在他的回答中提出的,使用一个对象来存储获取的数据。

我对你的代码做了一些改变,使它更"React方式"。我还没有测试过这个,因为我没有API密钥,但我相信你可以让它工作只需一些更改。

希望这对你有帮助。但如果没有,请把你的疑问作为评论,我会尽力帮助。

import React, { useState, useEffect } from "react";
import axios from "axios";
function App() {
const [city, setCity] = useState("");
const [appData,setAppData] = useState({});

const handleCityChange = (e) => {
e.preventDefault();
const cityInput = document.getElementById("city-input");
setCity(cityInput.value);
}
useEffect(async (e) => {
e.preventDefault();
const imageData = await axios.get(`https://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&appid=${OTHER_API_KEY}`);
const weatherData = await axios.get(`https://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&appid=${OTHER_API_KEY}`);
setAppData({ image: imageData.data.urls.regular, weather: weatherData.data });
},[city]);
return (
<div className="App">
{/* HEADER */}
<div className="bg-black w-full h-[600px]">
<img
src={city}
alt="city image"
className="w-full h-[600px] object-cover"
/>
{/* Search and Info */}
<div className="absolute w-full h-[600px] top-[0%] flex flex-col justify-center bg-gradient-to-t from-black">
<div className="flex justify-center py-4">
<h1 className="font-bold">Weather App</h1>
</div>
<div className="flex justify-center">
<input
id="city-input"
className="bg-transparent focus:outline-none placeholder:text-white"
type="text"
placeholder="Search a City..."
/>
<button onClick={handleCityChange}>New city</button>
</div>
</div>
</div>
{/* DATA */}
</div>
);
}
export default App;

最新更新