9.3. 公共工具方法
9.3.1. isResponse
从 hzero-front 的工具方法 getResponse
升级而来。在判断请求是否成功的同时允许接收一个泛型去定义返回值。
例:
import { isResponse } from 'hzero-front-apaas/lib/utils/request';
interface Person {
name: string;
}
function App() {
const [data, setData] = React.useState<Record<string, any>>();
React.useEffect(() => {
const fetchData = async () => {
const response = await request('/api/test');
if (isResponse<Person>(response)) {
setData(response); // response 类型为 Person
} else {
console.error(response); // response 类型为 any
}
};
fetchData();
}, []);
return (
<div>
{data?.name}
</div>
);
}
此方法维护者:
9.3.2. 请求取消
在 aPaas 项目中接口请求主要分为2种类型—— fetch
和 axios
。那么这两种请求的取消方式也不同。统一采用如下2种方式进行取消。
fetch 请求取消方式:
// 接口请求
async function sendQuestion(
body: { question: string },
options?: Record<string, any>, // 第二个参数必须预留 options 参数,用于添加取消请求的 token
) {
return request(`${lowcodeOrganizationURL({ route: HZERO_HMDE })}/xxx/chat`, {
method: 'POST',
body,
...options,
});
}
// 使用的组件
const App: React.FC<Props> = () => {
const { run, cancel } = useCancelRequest(sendQuestion); // 使用 useCancelRequest 包装请求方法
useEffect(() => {
run({ question: '你好' }); // 使用包装后的方法发起请求
}, []);
return (
<button type="button" onClick={()=> cancel()}>
取消
</button>
);
};
axios 请求取消方式(一般用于 DS 的接口请求):
const App: React.FC<Props> = () => {
const cancelRequestRef = useRef(axios.CancelToken.source());
const demoDs = useMemo(
() =>
new DataSet({
autoQuery: true,
//... 其他配置
transport: {
read: ({ data }) => {
return {
url: `${lowcodeOrganizationURL({ route: HZERO_HMDE })}/xxxxx`,
method: 'GET',
body: data,
cancelToken: cancelRequestRef.current.token,
};
},
},
}),
[]
);
return (
<button type="button" onClick={()=> cancelRequestRef.current.cancel()}>
取消
</button>
);
};
此方法维护者:
9.3.2. cachedRequest 函数式请求缓存
项目中虽然采用了 ahooks 中的 uesRequest 作为请求的 hook,但是 uesRequest
需要传入的缓存的 cacheKey
方法在 uesRequest
初始化的时候需要确定且无法在手动请求过程中实时变更。
同时项目中使用 uesRequest
发起请求的写法并不多, 所以封装了一个针对函数式请求缓存的方法 cachedRequest
, 在代码改动量最小的情况下, 实现接口请求缓存。
cachedRequest
会根据 cacheKey
对同时正在并发的请求
进行缓存, 后发起的请求会等待第一个发起请求的返回结果
。缓存有效时间默认 10 秒
(可以通过 options
参数进行配置)。在缓存有效时间内相同 cacheKey
的请求会复用上一轮请求的结果。缓存有效时间过后, 再调用方法会重新发起。
参数
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
request | 异步方法 | (...args: any[]) => Promise<any> | - |
cacheKey | 缓存唯一标识 | string | - |
options(可选) | 选项 | ICacheRequestOptions | - |
options
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
cacheResultMap(可选) | 缓存的结果 | Map<string, any> | _cacheResultMap |
cachePendingPromiseMap(可选) | 缓存的正在进行的接口请求 | Map<string, Promise<any>> | _cachePendingPromiseMap |
cacheTime(可选) | 缓存有效时间 | number | 1000 * 10 (10秒) |
使用案例
普通请求缓存
import { cachedRequest } from 'hzero-front-apaas/lib/utils/request';
// 模拟的一个接口请求
const fetchData = async ({id, keyword}) => {
return request(`/api/test/${id}?keyword=${keyword}`);
};
const App: React.FC<Props> = () => {
const [data, setData] = useState<any>();
useEffect(() => {
const query = {
id: '1',
keyword: 'test',
};
// 确定缓存标识(未提供物理隔离,推荐使用模块 + 方法名 + 参数序列化作为缓存标识)
const cacheKey = `hmde-fetchData-${JSON.stringify(query)}`;
// 对普通请求使用 cachedRequest 包装
cachedRequest(()=>fetchData(query), cacheKey).then((res) => {
setData(res);
});
}, []);
return (
<div>
{data?.name}
</div>
);
};
提供请求缓存空间以物理隔离避免缓存重复
import { cachedRequest } from 'hzero-front-apaas/lib/utils/request';
// 模拟的一个接口请求
const fetchData = async ({id, keyword}) => {
return request(`/api/test/${id}?keyword=${keyword}`);
};
const cacheResultMap = new Map<string, any>();
const cachePendingPromiseMap = new Map<string, Promise<any>>();
const App: React.FC<Props> = () => {
const [data, setData] = useState<any>();
useEffect(() => {
const query = {
id: '1',
keyword: 'test',
};
// 确定缓存标识(提供了物理隔离, 可以直接使用参数序列化作为缓存标识)
const cacheKey = JSON.stringify(query);
// 对普通请求使用 cachedRequest 包装
cachedRequest(()=>fetchData(query), cacheKey, {
cacheResultMap,
cachePendingPromiseMap,
}).then((res) => {
setData(res);
});
}, []);
return (
<div>
{data?.name}
</div>
);
};
此方法维护者: