运行 useEffect only one when a special 属性 改变了

Run useEffect only one when a special property changed

我想在特殊 属性 更改时更新渲染。本属性收入来自parents。我创建了一个名为 loader 的 useState 来处理我是否有数据的代码。如果加载程序为假,我的代码将调用 API,如果为真,则渲染数据。 首先,我以这种方式使用 useEffect。它没有更新渲染

useEffect(() => {
callApi();
}, []);

之后我就这样使用了useEffect。 props.coordinates 是一个 属性,我的代码在更改后应该更新。

  useEffect(() => {
    callApi();
    setLoader(false);
  }, [props.coordinates]);

但是我的代码在循环中,我的 API 密钥被阻止了。 你能告诉我我的错误是什么吗?

这是我的组件:

import React, { useEffect, useState } from "react";
import axios from "axios";
import ForcastHour from "./ForcastHour";
import "./WeatherHourlyForcast.css";

const WeatherHourlyForcast = (props) => {
  const [loader, setLoader] = useState(false);
  const [hourlyForcastData, setHourlylyForcastData] = useState(null);

  useEffect(() => {
    callApi();
    setLoader(false);
  }, [props.coordinates]);

  const showHourlyForcast = (response) => {
    console.log("showHourlyForcast", response.data.hourly);
    setHourlylyForcastData(response.data.hourly);
    setLoader(true);
  };

  function callApi() {
    let latitude = props.coordinates.lat;
    let longitude = props.coordinates.lon;
    const apiKey = "23422500afd990f6bd64b60f46cf509a";
    let units = "metric";
    let apiUrl = `https://api.openweathermap.org/data/2.5/onecall?lat=${latitude}&lon=${longitude}&appid=${apiKey}&units=${units}`;
    axios.get(apiUrl).then(showHourlyForcast);
    console.log("hourly", apiUrl);
  }

  if (loader) {
    return (
      <div className="row">
        <div className="col-md-6">
          <div className="row">
            {hourlyForcastData.map(function (hourlyforcast, index) {
              if (index < 4 && index > 0) {
                return (
                  <div
                    className="col-4 box-weather my-auto text-center"
                    key={index}
                  >
                    <ForcastHour data={hourlyforcast} />
                  </div>
                );
              }
            })}
          </div>
        </div>
        <div className="col-md-6">
          <div className="row">
            {hourlyForcastData.map(function (hourlyforcast, index) {
              if (index < 7 && index > 3) {
                return (
                  <div
                    className="col-4 box-weather my-auto text-center"
                    key={index}
                  >
                    <ForcastHour data={hourlyforcast} />
                  </div>
                );
              }
            })}
          </div>
        </div>
      </div>
    );
  } else {
    callApi();
    return null;
  }
};

export default WeatherHourlyForcast;

将依赖项数组添加到 useEffect(或任何其他挂钩...)的末尾时,如果每次渲染的值不等于前一个,则挂钩将再次 运行 .

因为props.coordinates是一个对象,而在JS中objA != objA == true,即使属性没有改变,React也不知道。

我的建议是使用值本身(假设它们是字符串或者数字等等)


  useEffect(() => {
    (async () => {
      await callApi();
      setLoader(false);
   })()
  }, [props.coordinates.lat, props.coordinates.lon]);

您可能会遇到的另一件事是 setLoader(false) 将在 callApi 完成之前被调用,因此将异步行为添加到挂钩

您可以像这样编写您的组件,并在组件挂载时调用 APIs。 API 调用在 latlon 值更改时发生。

import React, { useEffect, useState } from "react";
import axios from "axios";
import ForcastHour from "./ForcastHour";
import "./WeatherHourlyForcast.css";

const WeatherHourlyForcast = (props) => {
  const { coordinates : { lat, lon } } = props;
  const [loader, setLoader] = useState(false);
  const [hourlyForcastData, setHourlylyForcastData] = useState(null);

  useEffect(() => {
    callApi();
  }, [lat, lon]); //It's call the API's when the lat, lon values are changed

  const callApi = () => {
    setLoader(true);
    const latitude = lat;
    const longitude = lon;
    const apiKey = "23422500afd990f6bd64b60f46cf509a";
    const units = "metric";
    const apiUrl = `https://api.openweathermap.org/data/2.5/onecall?lat=${latitude}&lon=${longitude}&appid=${apiKey}&units=${units}`;
    axios.get(apiUrl).then((response) => {
      console.log(response.data);
      console.log(response.status);
      console.log(response.statusText);
      console.log(response.headers);
      console.log(response.config);
      console.log("showHourlyForcast", response.data.hourly);
      setHourlylyForcastData(response.data.hourly);
      setLoader(false);
    });
  };

  if (loader) {
    return (
      <div>
        <h1>Loading...</h1>
      </div>
    );
  }

  return (
    <div className="row">
      <div className="col-md-6">
        <div className="row">
          {hourlyForcastData.map(function (hourlyforcast, index) {
            if (index < 4 && index > 0) {
              return (
                <div
                  className="col-4 box-weather my-auto text-center"
                  key={index}
                >
                  <ForcastHour data={hourlyforcast} />
                </div>
              );
            }
          })}
        </div>
      </div>
      <div className="col-md-6">
        <div className="row">
          {hourlyForcastData.map(function (hourlyforcast, index) {
            if (index < 7 && index > 3) {
              return (
                <div
                  className="col-4 box-weather my-auto text-center"
                  key={index}
                >
                  <ForcastHour data={hourlyforcast} />
                </div>
              );
            }
          })}
        </div>
      </div>
    </div>
  );
};

export default WeatherHourlyForcast;