使用 react-promise-tracker 无限获取请求
infinite fetch request with react-promise-tracker
我正在使用提取 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 并且在某些时候服务器 returns 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;
};
我正在使用提取 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 并且在某些时候服务器 returns 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;
};