javascript - 使用 react-promise-tracker 的无限获取请求
问题描述
我正在使用 fetch API 从外部 API 获取数据。我想在请求获取数据时实现加载游标。为此,我正在尝试使用 react-promise-tracker 库。但是当使用库中的 trackPromise 时,获取会无限重复。
在此示例项目中更改注释代码时,您可以看到自己发生的错误(检查控制台,这一切都发生在 console.log 中): https ://codesandbox.io/s/tender-easley-szfxg?file=/src /App.tsx
基本上这有效:
export default function App() {
const get = (url: string) => {
let headers: {
Accept: string;
"Content-Type": string;
} = {
Accept: "application/ld+json",
"Content-Type": "application/json"
};
return fetch(url, {
method: "GET",
headers
} as RequestInit)
.then((res: Response) => {
if (res.ok) {
return res.json();
}
return Promise.reject(res);
})
.catch(Promise.reject.bind(Promise));
};
get("https://608bb5b6737e470017b752e2.mockapi.io/users")
.then(console.log)
.catch(console.log);
return <div>nothing</div>;
}
这不会:
import { usePromiseTracker, trackPromise } from "react-promise-tracker"; // ADDED CODE
export default function App() {
const { promiseInProgress } = usePromiseTracker({ area: "fetchDataGet" }); // ADDED CODE
const cursorStyle = () => { // ADDED CODE
return promiseInProgress ? { cursor: "wait" } : undefined; // ADDED CODE
}; // ADDED CODE
const get = (url: string) => {
let headers: {
Accept: string;
"Content-Type": string;
} = {
Accept: "application/ld+json",
"Content-Type": "application/json"
};
return trackPromise( // ADDED CODE
fetch(url, {
method: "GET",
headers
} as RequestInit)
.then((res: Response) => {
if (res.ok) {
return res.json();
}
return Promise.reject(res);
})
.catch(Promise.reject.bind(Promise)),
"fetchDataGet" // ADDED CODE
);
};
get("https://608bb5b6737e470017b752e2.mockapi.io/users")
.then(console.log)
.catch(console.log);
return <div style={cursorStyle()}>nothing</div>;
}
第二个代码的输出是几个 console.log 当它应该只有 1 并且在某些时候服务器返回一个 429 错误(这很正常,这只是服务器安全)
解决方案
在您的第二个示例中,您没有使用useEffect
而是get()
在组件主体内部调用(这意味着每次组件呈现时都会调用它)。usePromiseTracker
将触发状态更改,因此每次您的请求承诺解决时都会重新呈现。这肯定会导致无限循环的获取。
一般来说,您永远不应该无条件地触发组件体内的任何副作用(如获取数据)。它应该始终位于仅在特定时间点运行的效果内或事件处理程序内。
在这种特定情况下,您可以通过扭曲get()
调用效果来解决它:
useEffect(() => {
get("https://608bb5b6737e470017b752e2.mockapi.io/users")
.then(console.log)
.catch(console.log);
}, []); // will only be called once after mounting
如果你的项目中经常有这种代码,你应该提取一个自定义钩子,它在内部执行此操作并隐藏usePromiseTracker
,这样你就不必在每次想要获取某些东西时显式使用它:
const useFetch = (area, url, options) => {
const { promiseInProgress } = usePromiseTracker({area});
useEffect(() => {
trackPromise(
fetch(url, options)
.then(res => res.ok ? res.json() : Promise.reject(res))
.catch(Promise.reject.bind(Promise)),
area,
);
}, []);
return promiseInProgress;
};
推荐阅读
- sql - AWS IoT 中心 SQL:意外字符“$”
- java - 在 Elastic Beanstalk 上使用 catalina.out 缓解存储问题
- sql-server - 从 Onedrive 访问文件并使用 SSIS 包 2015 加载到 sql server 表
- python - Pytest 在使用 tox 时显示“ModuleNotFoundError”
- c# - 反序列化异常
- android - 视频会议的缩放 sdk 已正确集成,但包含摄像头、音频按钮的顶部布局缺失
- java - 有什么方法可以让我的 ps4 控制振动/隆隆声?用java
- php - 如何使用相同的输入类型名称更新多个mysql行
- java - 问:在 BPEL 中嵌入 Java 是不好的做法吗?
- angular - Angular 6 时间选择器似乎切断了 MM 显示的结束