You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何扩展自定义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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 14:03:22