reactjs 如何在React中限制获取API的速率?

relj7zay  于 2023-02-08  发布在  React
关注(0)|答案(3)|浏览(141)

我有一个Vite.js应用程序React Template。在我的一个组件中,我想从https://wheretheiss.at/w/developer API获取一些数据。我使用的是useEffect。现在,文档提到速率限制为每秒1个请求。下面是我的代码:

import { useState, useEffect } from "react";
import axios from "axios";

export default function Info() {
  const [info, setInfo] = useState({
    longitude: 0,
    latitude: 0,
    altitude: 0,
    velocity: 0,
    visibility: "",
  });

  const getCoords = async () => {
    const data = await axios({
      method: "get",
      url: "https://api.wheretheiss.at/v1/satellites/25544",
    });

    return data;
  };

  useEffect(() => {
    fetch("https://api.wheretheiss.at/v1/satellites/25544")
      .then((res) => res.json())
      .then((data) => {
        const lat = data.latitude;
        const long = data.longitude;
        const alt = data.altitude * 0.62137119;
        const vel = data.velocity * 0.62137119;
        const vis = data.visibility;

        setInfo({
          longitude: long.toFixed(4),
          latitude: lat.toFixed(4),
          altitude: alt.toFixed(4),
          velocity: vel.toFixed(2),
          visibility: vis === "daylight" ? "not visible" : "visible",
        });
      });
  }, [info]);

  return (
    <section className="info">
      <hr />
      <ul>
        <li>
          <strong>Latitude: </strong>
          <span>{info.latitude}°</span>
        </li>
        <li>
          <strong>Longitude: </strong>
          <span>{info.longitude}°</span>
        </li>
        <li>
          <strong>Altitdude: </strong>
          <span>{info.altitude} miles</span>
        </li>
        <li>
          <strong>Velocity: </strong>
          <span>{info.velocity} mph</span>
        </li>
        <li>
          <strong>Visibility: </strong>
          <span>{info.visibility}</span>
        </li>
      </ul>
    </section>
  );
}

我知道将info状态设置为useEffect钩子的依赖项数组将决定React在无限循环中重新呈现组件。我怎样才能将fecting限制为每秒一次?我不能将dependie数组设置为[],因为我想不断地获取数据,因为纬度、经度等每秒都在变化。我也不能让它保持这样,因为应用程序会抛出以下错误:
未被抓住的(承诺中的):对象{...,消息:"请求失败,状态代码为429 "}
这意味着我的应用发出的许多请求超过了速率限制。当我收到此错误时,我的坐标不再重新渲染,它们保持不变。
你知道吗?

aurhwmvo

aurhwmvo1#

您可以在您的环境中使用'axios-retry' npm包,它具有在您的环境中使用所需的功能。

0qx6xfy6

0qx6xfy62#

**第1步:**导入React去抖动库npm i loadash

现在使用loadash的去抖动功能去抖动,这样功能将仅运行1秒,因此请求也将限制为每秒1req
下面是修改后的代码:

import { useState, useEffect } from "react";
import axios from "axios";
import { debounce } from 'loadash';

export default function Info() {
  const [info, setInfo] = useState({
    longitude: 0,
    latitude: 0,
    altitude: 0,
    velocity: 0,
    visibility: "",
 });

  const getCoords = async () => {
    const data = await axios({
      method: "get",
      url: "https://api.wheretheiss.at/v1/satellites/25544",
    });

    return data;
  };

let debouncedReq = debounce(()=>{
 fetch("https://api.wheretheiss.at/v1/satellites/25544")
      .then((res) => res.json())
      .then((data) => {
        const lat = data.latitude;
        const long = data.longitude;
        const alt = data.altitude * 0.62137119;
        const vel = data.velocity * 0.62137119;
        const vis = data.visibility;

        setInfo({
          longitude: long.toFixed(4),
          latitude: lat.toFixed(4),
          altitude: alt.toFixed(4),
          velocity: vel.toFixed(2),
          visibility: vis === "daylight" ? "not visible" : "visible",
        });
      });
}, 1000) // now the function is debounced for 1000ms

  useEffect(() => {
   debouncedReq()
  }, [info]);

  return (
    <section className="info">
      <hr />
      <ul>
        <li>
          <strong>Latitude: </strong>
          <span>{info.latitude}°</span>
        </li>
        <li>
          <strong>Longitude: </strong>
          <span>{info.longitude}°</span>
        </li>
        <li>
          <strong>Altitdude: </strong>
          <span>{info.altitude} miles</span>
        </li>
        <li>
          <strong>Velocity: </strong>
          <span>{info.velocity} mph</span>
        </li>
        <li>
          <strong>Visibility: </strong>
          <span>{info.visibility}</span>
        </li>
      </ul>
    </section>
  );
}
eqqqjvef

eqqqjvef3#

您现有的代码依赖于fetch调用的成功,之后会调度另一个调用(由使用新数据调用setInfo触发),这些调用会被调度为一个接一个地运行,没有任何延迟,这会导致快速达到速率限制。
wheretheiss.at速率限制在their API page上有粗略的记录,但他们也指出您应该查看他们的服务器返回的X-Rate-Limit-*头文件以了解更多信息:

X-Rate-Limit-Limit: 350
X-Rate-Limit-Remaining: 193
X-Rate-Limit-Interval: 5 minutes

这意味着您可以比每秒稍多地查询,以便使用setInterval来调度API调用:

useEffect(() => {
  const interval = setInterval(() => {
    fetch('https://api.wheretheiss.at/v1/satellites/25544')
        .then((res) => res.json())
        .then((data) => {
          const lat = data.latitude;
          const long = data.longitude;
          const alt = data.altitude * 0.62137119;
          const vel = data.velocity * 0.62137119;
          const vis = data.visibility;

          setInfo({
            longitude: long.toFixed(4),
            latitude: lat.toFixed(4),
            altitude: alt.toFixed(4),
            velocity: vel.toFixed(2),
            visibility: vis === 'daylight' ? 'not visible' : 'visible',
          });
        });
  }, 1_000);
  return () => { clearInterval(interval) };
}, [setInfo])

Stackblitz link

相关问题