【发布时间】:2021-07-23 14:51:05
【问题描述】:
我正在使用 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错误(这很正常,这只是服务器安全)
【问题讨论】:
-
您在渲染期间无条件调用
get(...)。每次你的组件重新渲染时,你都会触发一个新的请求,并且只要 promise 解决/被拒绝,它就会重新渲染。您可能希望将其包装在useEffect中。 -
如果你想省去很多麻烦,你应该看看react-query,它提供了专门用于获取数据的钩子。
-
@trixn 公平点,但这只是本例中的情况,在我的实际代码中,我使用的是 useEffect。在此示例中,组件不会重新呈现,因为提取只会触发 console.log
-
在第二个示例中,您没有使用
useEffect,而是在组件主体内部调用get()(这意味着每次组件呈现时都会调用它)。usePromiseTracker将触发状态更改,因此每次您的请求承诺解决时都会重新渲染。这肯定会导致无限循环的获取,这正是您要解决的问题。我在这里错过了什么? -
一般来说,你永远不应该无条件地触发组件体内的任何副作用(如获取数据)。它应该始终位于仅在特定时间点运行的效果内或事件处理程序内。
标签: javascript reactjs promise fetch