跳到主要内容

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种类型—— fetchaxios。那么这两种请求的取消方式也不同。统一采用如下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(可选)缓存有效时间number1000 * 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>
);
};
此方法维护者:黄振敏