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

Next.js + TypeScript自定义useFetch钩子URL类型错误解决

解决Next.js + TypeScript中useFetch钩子的类型不匹配问题

问题场景

使用Next.js搭配TypeScript开发时,自定义useFetch钩子调用API时出现类型不匹配错误,错误提示:

Argument of type 'string' is not assignable to parameter of type 'FetchParams'.ts(2345)

错误出现在组件调用useFetch的语句中:

const { data }: any = useFetch(`https://api.aladhan.com/v1/calendarByCity?city=${city}&country=${country}&method=5&month=${month}&year=${year}`)

错误原因

  1. 参数类型定义错误:自定义钩子useFetch的参数被定义为FetchParams类型(一个包含url属性的对象),但实际调用时传入的是字符串格式的URL,导致类型不匹配。
  2. React钩子规范问题:useFetch被定义为async函数,违反React钩子不能是异步函数的规则。
  3. 状态类型不明确:useState初始化时使用空字符串,与API返回的JSON数据类型不匹配,且大量使用any类型失去TypeScript的类型校验优势。

修复方案

1. 修正useFetch钩子的类型与实现

将钩子的参数改为string类型,移除冗余的FetchParams类型;改用useEffect处理异步请求,遵循React钩子规则;给状态指定泛型类型:

"use client"
import { useState, useEffect } from "react";

// 定义API返回数据的基础类型,建议后续替换为具体接口结构
type ApiResponse = any;

export default function useFetch<T = ApiResponse>(url: string) {
  const [data, setData] = useState<T | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<Error | null>(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const res = await fetch(url);
        if (!res.ok) throw new Error(`HTTP error! status: ${res.status}`);
        const result = await res.json() as T;
        setData(result);
      } catch (err) {
        setError(err as Error);
        console.log("error", err);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [url]);

  return { data, loading, error };
}

2. 修正Pray组件的调用逻辑

移除组件内冗余的状态,正确在组件顶层调用useFetch,并明确API返回数据的类型:

import useFetch from '@/Hooks/useFetch';
import { useState, useEffect } from 'react';

// 定义API返回的具体类型,替代any以获得类型校验
type PrayerCalendarResponse = {
  data: Array<{
    date: { gregorian: { date: string } },
    timings: { Fajr: string; Dhuhr: string; Asr: string; Maghrib: string; Isha: string }
  }>
};

export default function Pray() {
  // Date methods
  const date = new Date();
  const month = date.getMonth() + 1;
  const year = date.getFullYear();

  const [country, setCountry] = useState('eg');
  const [city, setCity] = useState('cairo');
  // 动态生成请求URL
  const apiUrl = `https://api.aladhan.com/v1/calendarByCity?city=${city}&country=${country}&method=5&month=${month}&year=${year}`;

  // 在组件顶层调用useFetch,传入明确的类型泛型
  const { data, loading, error } = useFetch<PrayerCalendarResponse>(apiUrl);

  // 监听数据变化做后续处理
  useEffect(() => {
    if (data) {
      console.log(data);
      // 这里可添加数据处理逻辑
    }
  }, [data]);

  if (loading) return <div>加载中...</div>;
  if (error) return <div>请求出错:{error.message}</div>;

  return (
    <div>
      {data?.data.map((item, index) => (
        <div key={index}>
          <h3>{item.date.gregorian.date}</h3>
          <p>晨礼:{item.timings.Fajr}</p>
          <p>晌礼:{item.timings.Dhuhr}</p>
          <p>晡礼:{item.timings.Asr}</p>
          <p>昏礼:{item.timings.Maghrib}</p>
          <p>宵礼:{item.timings.Isha}</p>
        </div>
      ))}
    </div>
  );
}

关键说明

  • 类型明确化:定义PrayerCalendarResponse类型约束API返回数据,替代any,提升代码可维护性和类型安全性。
  • 钩子规范:确保useFetch遵循React钩子规则,仅在组件顶层调用。
  • 状态扩展:添加loading和error状态,便于处理请求的不同阶段,提升用户体验。

内容的提问来源于stack exchange,提问作者Ahmed Essam

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 21:35:29