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

React传递参数时useFetch自定义Hook失效问题求助

问题分析与修复方案

核心问题1:Fetch Aborted 错误

Calendar组件中每次渲染都会创建新的FormData实例,而useFetch的useEffect依赖了formData(引用类型)。由于每次渲染生成的FormData都是新对象,会不断触发useEffect执行,旧请求被AbortController终止,最终出现"Fetch aborted"错误。

同时,App组件中apiData是异步加载的,初始值为null,Calendar组件初始化时apiData未就绪,直接创建FormData会导致apiData.schoolGroup等属性报错,间接引发组件重复渲染。

核心问题2:第三方API POST请求失效

当前useFetch默认强制解析响应为JSON,如果第三方API返回的不是JSON格式,会抛出错误导致请求失败。另外,需确认第三方API是否支持multipart/form-data类型的请求(FormData默认触发该类型)。


修复步骤

1. 修复Calendar组件的FormData重复创建问题

使用useMemo缓存FormData,仅当依赖的user或apiData变化时才重新生成,避免不必要的渲染触发:

import React, { useMemo } from 'react'
import useFetch from '../Components/useFetch';

const Calendar = ({user, apiData}) => {
    // 仅当user或apiData变化时,才创建新的FormData
    const apiFormData = useMemo(() => {
        // 确保user和apiData都已加载完成
        if (!user || !apiData) return null;
        
        const formData = new FormData();
        formData.append('school_group', apiData.schoolGroup);
        formData.append('db', apiData.db);
        formData.append('student_idx', user.calendarId);
        return formData;
    }, [user, apiData]);

    // 只有当apiFormData存在时,才发起请求
    const {data: calendar, error: calError, isPending: calIsPending} = useFetch(
        apiFormData ? 'https://MY-API-LINK' : null, 
        apiFormData
    );

    return (
        <div>
            {calError && <div>{calError}</div>}
            {calIsPending && <div>Loading...</div>}
            {calendar && (
                <div>
                    <h2>Calendar</h2>
                    {console.log(calendar)}
                </div>
            )}
        </div>
    )
}

export default Calendar

2. 优化useFetch,兼容非JSON响应

修改useFetch,增加响应类型判断,避免强制解析JSON导致的错误:

import { useState, useEffect } from 'react';

const useFetch = (url, formData = null) => {
    const [data, setData] = useState(null);
    const [isPending, setIsPending] = useState(true);
    const [error, setError] = useState(null);

    useEffect(() => {
        // 如果url为空,直接终止逻辑
        if (!url) {
            setIsPending(false);
            return;
        }

        const abortCont = new AbortController();

        const fetchData = async () => {
            try {
                const fetchOptions = {
                    method: 'GET',
                    signal: abortCont.signal,
                };

                if (formData) {
                    fetchOptions.method = 'POST';
                    fetchOptions.body = formData;
                    // FormData会自动设置Content-Type为multipart/form-data,无需手动添加
                }

                const response = await fetch(url, fetchOptions);

                if (!response.ok) {
                    throw Error(`请求失败:${response.status} ${response.statusText}`);
                }

                // 尝试解析JSON,如果失败则返回文本
                let responseData;
                try {
                    responseData = await response.json();
                } catch {
                    responseData = await response.text();
                }

                setData(responseData);
                setIsPending(false);
                setError(null);
            } catch (err) {
                if (err.name !== 'AbortError') {
                    setIsPending(false);
                    setError(err.message);
                }
            }
        };

        fetchData();

        return () => abortCont.abort();
    }, [url, formData]);

    return { data, isPending, error };
};

export default useFetch;

3. 补充App组件的加载状态处理

确保Calendar组件仅在apiData就绪后才接收有效数据,避免初始渲染时的错误:

// 在App.js的Calendar路由中,增加apiData的加载判断
<Route path="/calendar" element={
    apiIsPending ? <div>Loading API config...</div> : 
    <Calendar user={user} apiData={apiData}/>
} />

额外排查点

  • 确认第三方API是否允许跨域请求(可在浏览器控制台Network面板查看CORS错误),若存在跨域问题,需通过后端代理转发请求。
  • 检查FormData中的参数名是否与API要求完全一致(比如是否是school_group还是schoolGroup)。

内容的提问来源于stack exchange,提问作者Furkan Karaoglu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 13:44:55