设计思路
- 输入输出类型定义:
- 输入类型:定义请求的参数类型,比如请求的URL、请求方法、请求体等。
- 输出类型:包含数据请求的不同状态(loading、success、error)以及对应的数据或错误信息。
- 处理不同数据请求状态:
- loading:在发起请求时,将状态设为loading。
- success:请求成功后,将状态设为success,并存储返回的数据。
- error:请求失败时,将状态设为error,并存储错误信息。
- 缓存处理:使用一个变量来存储已经请求过的数据,下次请求相同参数时,直接从缓存中返回数据。
- 重试机制:在请求失败时,根据设定的重试次数进行重试。
代码实现
import { useState, useEffect } from'react';
// 定义请求参数类型
type RequestParams = {
url: string;
method?: 'GET' | 'POST' | 'PUT' | 'DELETE';
body?: any;
};
// 定义请求返回的数据类型
type ResponseData = any;
// 定义请求状态
type RequestStatus = 'loading' |'success' | 'error';
// 定义Hook返回的类型
type UseDataFetchResult = {
status: RequestStatus;
data: ResponseData | null;
error: Error | null;
};
// 自定义Hook
const useDataFetch = (params: RequestParams, retryCount = 3, cache: { [key: string]: ResponseData } = {}): UseDataFetchResult => {
const [status, setStatus] = useState<RequestStatus>('loading');
const [data, setData] = useState<ResponseData | null>(null);
const [error, setError] = useState<Error | null>(null);
const cacheKey = JSON.stringify(params);
useEffect(() => {
if (cache[cacheKey]) {
setStatus('success');
setData(cache[cacheKey]);
return;
}
const controller = new AbortController();
const fetchData = async () => {
let currentRetry = 0;
while (currentRetry < retryCount) {
try {
const response = await fetch(params.url, {
...(params.method && { method: params.method }),
...(params.body && { body: JSON.stringify(params.body) }),
signal: controller.signal
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
cache[cacheKey] = result;
setStatus('success');
setData(result);
break;
} catch (e: any) {
if (e.name === 'AbortError') {
return;
}
currentRetry++;
if (currentRetry === retryCount) {
setStatus('error');
setError(e);
}
}
}
};
fetchData();
return () => {
controller.abort();
};
}, [params, retryCount, cache]);
return { status, data, error };
};
export default useDataFetch;