简体   繁体   English

React,根据第一个 api 调用设置的 state 进行第二个 API 调用

[英]React, make a second API call based on a state set by a first api call

I am trying to build a weather app with OpenWeather API. I have to get the latitude and longitude based on a first API call that define the location by search.我正在尝试使用 OpenWeather API 构建一个天气应用程序。我必须根据通过搜索定义location的第一个 API 调用来获取latitudelongitude I have tried async/await and useEffect hook but failed in both cases.我尝试了async/awaituseEffect钩子,但在这两种情况下都失败了。

My code is below.我的代码如下。 What am I missing?我错过了什么?

import { useState } from "react";

const api = {
  key: `${process.env.REACT_APP_API_KEY}`,
  base: "https://api.openweathermap.org/data/2.5/",
};

function App() {
  const [query, setQuery] = useState("");
  const [weather, setWeather] = useState({});
  const [location, setLocation] = useState({ lat: "", lon: "" });
  const [following, setFollowing] = useState([]);

  const search = async (e) => {
    if (e.key === "Enter") {
      await fetch(
        `${api.base}weather?q=${query}&units=metric&appid=${api.key}&lang=tr`
      )
        .then((res) => res.json())
        .then((result) => {
          setWeather(result);
          setQuery("");
          setLocation(result.coord);
          console.log(result);
          searchFollowing();
        });
    }
  };

  const searchFollowing = async () => {
    await fetch(
      `${api.base}onecall?lat=${location.lat}&lon=${location.lon}&units=metric&exclude=hourly,minutely&appid=${api.key}`
    )
      .then((res) => res.json())
      .then((result2) => {
        const array = result2.daily.slice(1, 6);
        console.log(following);
        setFollowing(array);
        // following == array
      });
  };

  const integer = (number) => {
    return Math.floor(Math.round(number));
  };

  const mapped = (following) => {
    following = [...following];
    return following.map((item, idx) => {
      const icon = item.weather[0].icon;
      const day = integer(item.temp.day);
      const night = integer(item.temp.night);
      return (
        <div key={idx} className="box">
          <img
            src={`http://openweathermap.org/img/wn/${icon}.png`}
            alt="weather"
            width={80}
            height={80}
          />
          <h3>Day {day} °C</h3>
          <h3>Night {night} °C</h3>
        </div>
      );
    });
  };

  const dateBuild = (d) => {
    let months = [
      "January",
      "February",
      "March",
      "April",
      "May",
      "June",
      "July",
      "August",
      "September",
      "October",
      "November",
      "December",
    ];
    let days = [
      "Sunday",
      "Monday",
      "Tuesday",
      "Wednesday",
      "Thursday",
      "Friday",
      "Saturday",
    ];

    let day = days[d.getDay()];
    let date = d.getDate();
    let month = months[d.getMonth()];
    let year = d.getFullYear();

    return `${day} ${date} ${month} ${year}`;
  };

  return (
    <div
      className={
        typeof weather.main !== "undefined"
          ? weather.main.temp > 25
            ? "App hot"
            : weather.main.temp < 25 && weather.main.temp > 5
            ? "App warm"
            : "App"
          : "App"
      }
    >
      <main>
        <div className="search-box">
          <input
            type="text"
            className="search-bar"
            placeholder="Search for a location..."
            onChange={(e) => setQuery(e.target.value)}
            onKeyPress={search}
            value={query}
          />
        </div>
        {typeof weather.main != "undefined" ? (
          <div>
            <div className="location-box">
              <div className="location">
                {weather.name}, {weather.sys.country}
              </div>
              <div className="date"> {dateBuild(new Date())}</div>
            </div>
            <div className="weather-box">
              <div className="temp">
                {Math.round(weather.main.temp)}°C
                <img
                  src={`http://openweathermap.org/img/wn/${weather.weather[0].icon.slice(
                    0,
                    2
                  )}d.png`}
                  alt="weather"
                  width={80}
                  height={80}
                />
              </div>
              <div className="weather">
                <p>
                  <span>Hissedilen</span>
                  {Math.floor(weather.main.feels_like)} °C
                </p>
                <p>
                  <span>Şu an</span>
                  {weather.weather[0].description}
                </p>
                <p>
                  <span>Basınç</span>
                  {weather.main.pressure} mb
                </p>
                <p>
                  <span>Rüzgar </span>
                  {Math.floor(weather.wind.speed)} km/h
                </p>
                <p>
                  <span>En fazla</span>
                  {Math.floor(weather.main.temp_max)} °C
                </p>
                <p>
                  <span>En az</span>
                  {Math.floor(weather.main.temp_min)} °C
                </p>
              </div>
            </div>
            <div className="followingdays">{mapped(following)}</div>
          </div>
        ) : (
          ""
        )}
      </main>
    </div>
  );
}

export default App;

What you are missing is that when you are calling searchFollowing() , React did not yet re-render, therefore location wouldn't be updated.您缺少的是,当您调用searchFollowing()时,React 尚未重新渲染,因此不会更新location You could have an useEffect that would listen to location , and call searchFollowing() there when location.lat and location.lon are defined:你可以有一个useEffect来监听location ,并在location.latlocation.lon被定义时调用searchFollowing()

useEffect(()=>{
  if(location.lat && location.lon){
    searchFollowing();
  }
}, [location])

Then remove searchFollowing() call inside search function, as now you call it inside the above useEffect .然后在search function 中删除 searchFollowing searchFollowing()调用,就像现在在上面的useEffect中调用它一样。

在此处输入图像描述

The code below solved the problem thanks to @yousoumar.感谢@yousoumar,下面的代码解决了这个问题。 I will try second one.我会尝试第二个。

  useEffect(()=>{
  
    if(location.lat && location.lon){
      searchFollowing();
    }
  }, [location])

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何根据第一个响应进行第二个API调用? - How to make a second API call based on the first response? 如何根据从第一次获得的值进行第二次 API 调用。 使用 React 和 useEffect 钩子 - How to Make A second API call based on the value gotten from the first. with React and useEffect hooks 当第一次在 React 中使用 Axios 没有错误时进行第二次 api 调用 - Make second api call when there is no error on the first using Axios in React 如何使用 React 在 Apollo 客户端中从第一个 api 调用收到的数据进行第二个 api 调用? - How to make a second api call with data received from the first api call in Apollo client with React? React-Redux:在设置 state 后调用 api - React-Redux: Make api call after set state 在api调用中更新设置状态 - updating set state in api call react React 将状态设置为 API 调用的结果 - React set a state to the result of an API call React.JS,如何使用来自第二个 API 调用的数据编辑第一个 API 调用的响应? - React.JS, how to edit the response of a first API call with data from a second API call? 使用 React Hooks 在第二次渲染时调用 API - Make an API call on second render using React Hooks 在 React 中,如何进行单个 api 调用,将结果设置为 state 变量,并显示它? - In React, how can I make a single api call, set the result to a state variable, and display it?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM