如何扩展自定义React Hook以支持任意数量泛型Fetch函数并返回对应元组
扩展React Hook支持任意数量Fetch函数
需求说明
现有自定义Hook useFetchMultipleDataMunicipio 仅支持传入2个泛型Fetch函数,返回对应响应数据的元组及辅助变量。需要扩展为支持任意数量同类型Fetch函数,且返回数据元组的类型与各函数响应类型严格匹配。
解决方案
核心思路
通过TypeScript的可变长度泛型元组和类型推导,实现对任意数量Fetch函数的类型支持:
- 定义统一的Fetch函数类型别名,简化代码结构
- 使用泛型约束
T extends readonly FetchFunc[]接收任意数量的Fetch函数 - 自定义类型工具
DataTuple<T>,从传入的Fetch函数元组中提取响应数据类型,生成对应的数据元组类型 - 调整
useState、Promise.all的处理逻辑,适配可变长度的参数和返回值
完整实现代码
import { useState, useEffect } from 'react'; import { AxiosPromise } from 'axios'; import _ from 'lodash'; // 请替换为实际的上下文导入路径 import { IMunicipioRouteProps, useMunicipioContext } from './path-to-municipio-context'; import { IPrestacaoContextProps, usePrestacaoContext } from './path-to-prestacao-context'; import { ISettings, useSettingsContext } from './path-to-settings-context'; // 统一的Fetch函数类型别名 type FetchFunc<T = unknown> = ( routeProps: IMunicipioRouteProps, prestacaoContext: IPrestacaoContextProps, settings: ISettings ) => AxiosPromise<T>; // 类型工具:从Fetch函数元组提取响应数据类型,生成对应数据元组 type DataTuple<T extends readonly FetchFunc[]> = { [K in keyof T]: Awaited<T[K]>['data']; }; export function useFetchMultipleDataMunicipio<T extends readonly FetchFunc[]>( ...fetchFuncs: T ) { const routeProps = useMunicipioContext().municipioRouteProps; const prestacaoContext = usePrestacaoContext(); const { settings } = useSettingsContext(); const [dataTuple, setDataTuple] = useState<DataTuple<T> | undefined>(); const [loading, setLoading] = useState(true); useEffect(() => { if (_.isEmpty(routeProps) || prestacaoContext.loading) { return; } // 批量调用所有传入的Fetch函数 const requests = fetchFuncs.map(func => func(routeProps, prestacaoContext, settings)); Promise.all(requests) .then((responses) => { // 提取每个响应的data字段,组成类型匹配的元组 const newDataTuple = responses.map(res => res.data) as DataTuple<T>; setDataTuple(newDataTuple); }) .finally(() => { setLoading(false); }); return () => { setDataTuple(undefined); setLoading(true); }; }, [routeProps, prestacaoContext.loading, fetchFuncs]); return { dataTuple, loading, routeProps, prestacaoContext, settings }; }
用法示例
// 示例Fetch函数,返回不同类型的响应 const fetchUsers = (routeProps: IMunicipioRouteProps, ctx: IPrestacaoContextProps, settings: ISettings) => { return axios.get<User[]>('/api/users'); }; const fetchPosts = (routeProps: IMunicipioRouteProps, ctx: IPrestacaoContextProps, settings: ISettings) => { return axios.get<Post[]>('/api/posts'); }; // 使用扩展后的Hook,类型自动推导 const { dataTuple, loading } = useFetchMultipleDataMunicipio(fetchUsers, fetchPosts); // dataTuple类型会被推导为 [User[], Post[]] if (!loading && dataTuple) { const [users, posts] = dataTuple; // 可安全使用users和posts,类型完全匹配 }
内容的提问来源于stack exchange,提问作者paternostrox
相关产品推荐
相关产品推荐

