我正在创建一个钩子,使一个API请求获取统计数据。然而,当您浏览月份时,它还没有从上一个请求中检索到数据,它开始获取下一个请求,导致统计数据在不断刷新时跳转。我已经在钩子中添加了cancelToken,但没有成功。
我希望有人能帮助我,告诉我我错过了什么。
钩子代码:
import { atom, useAtom } from "jotai";
import axios from "axios";
import queryString from "query-string";
// Types
// import { MonthData, RevenueFunnelTypes, TotalsData } from "../../lib/types";
import {
Revenue,
RevenueQ,
RevenueFunnelTypes,
TotalCardsTypes,
} from "../../lib/types";
export type Status = "idle" | "loading";
export type Values = {
revenueFunnel: RevenueFunnelTypes;
totals: TotalCardsTypes;
revenue: Revenue | null;
revenueQ: RevenueQ | null;
// month: MonthData[];
};
export const rowsStatusAtom = atom<Status>("idle");
type ApiRowsResponse = {
body: any;
};
type State = {
values: Values;
status: Status;
actions: {
get: (
type: "revenue" | "revenue-quarters" | "revenue-funnel" | "totals",
date?: string
) => Promise<State["values"]>;
};
};
export interface sortRowsProps {
id: number;
order: number;
}
// Services
const createApiUrl = (route?: string, params?: any) => {
return queryString.stringify({
path: route,
...params,
});
};
export default function useStats(): State {
const [values, setValues] = useAtom(valuesAtom);
const [status, setStatus] = useAtom(rowsStatusAtom);
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
const getCurrentValues = async function (
type: "revenue" | "revenue-quarters" | "revenue-funnel" | "totals",
date?: string
): Promise<ApiRowsResponse | any> {
const url = createApiUrl("statistics", {
type: type,
date,
});
return axios
.get(`?${url}`, {
cancelToken: source.token
})
.then(function (response) {
return response.data;
})
.catch(function (thrown) {
if (axios.isCancel(thrown)) {
console.log('Request canceled', thrown.message);
} else {
// handle error
}
})
};
// Actions
// Get the current rows from the server
const get = async (
type: "revenue" | "revenue-quarters" | "revenue-funnel" | "totals",
date?: string
): Promise<State["values"]> => {
setStatus("loading");
const data = await getCurrentValues(type, date);
if (type === "revenue-funnel") {
setValues((prevState) => ({
...prevState,
revenueFunnel: data.body,
}));
} else if (type === "revenue") {
setValues((prevState) => ({
...prevState,
revenue: data.body,
}));
} else if (type === "revenue-quarters") {
setValues((prevState) => ({
...prevState,
revenueQ: data.body,
}));
} else if (type === "totals") {
setValues((prevState) => ({
...prevState,
totals: data.body,
}));
}
setStatus("idle");
return data.body;
};
return {
values,
status,
actions: {
get,
},
};
}
导航功能如下:
useEffect(() => {
if (loading && state === 0) {
actions.get("totals").then(() => {
setLoading(false);
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [loading, state]);
// Functions
const goToNextMonth = () => {
setLoading(true);
const updatedDate = moment(selectedDate).add(1, 'month').format('YYYY-MM-DD');
setSelectedDate(updatedDate);
actions.get("totals", updatedDate).then(() => setLoading(false));
};
const goToPreviousMonth = () => {
setLoading(true);
const updatedDate = moment(selectedDate).subtract(1, 'month').format('YYYY-MM-DD');
setSelectedDate(updatedDate);
actions.get("totals", updatedDate).then(() => setLoading(false));
};
创建一个Sandbox作为演示:https://codesandbox.io/s/axioscancelrequest-jdstpz?file=/src/App.tsx
尽可能低地禁用缓存和节流。
2条答案
按热度按时间4ioopgfo1#
您永远不会取消先前的请求。通过禁用前一个(如果存在)来启动每个请求,生成一个新的令牌源,并将其保存在
ref
(tokenSource
)上,以便下一个请求可以取消它:但是,
CancelToken
已被弃用,您应该使用标准的AbortController
:jutyujz02#
根据加载状态,您可以有条件地停止用户调用下一个请求