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

React中自定义useGetApi钩子参数需预处理时的正确调用方案

解决方案:复用现有自定义钩子,无需新增

首先,你遇到的错误是因为违反了React钩子的核心规则:钩子必须在函数组件的顶层作用域或自定义钩子的顶层作用域调用,不能嵌套在useEffect、条件判断等回调函数内部。

不用单独编写新钩子,只需要调整现有钩子的实现和使用方式,就能完美复用。

第一步:修复原useGetApi的bug

你的原钩子存在两个问题:

  1. useEffect的依赖是JSON.stringify(data),这会导致每次data更新就重新触发请求,进而再次更新data,形成无限循环;
  2. 没有处理组件卸载时的请求取消,可能造成内存泄漏。

修改后的useGetApi:

import { useState, useEffect } from 'react';
import axios from 'axios';

export const useGetApi = (link) => {
    const [data, setData] = useState();
    const [loading, setLoading] = useState(true);

    useEffect(() => {
        // 没有link时直接返回,避免无效请求
        if (!link) return;
        
        const cancelToken = axios.CancelToken.source();
        const handleFetch = async () => {
            try {
                setLoading(true);
                const response = await axios.get(link, { cancelToken: cancelToken.token });
                setData(response.data.data);
            } catch (err) {
                // 忽略取消请求的错误,只处理真实异常
                if (!axios.isCancel(err)) {
                    console.error('API请求失败:', err);
                }
            } finally {
                // 请求无论成功失败,都结束loading状态
                setLoading(false);
            }
        };

        handleFetch();

        // 组件卸载或link变化时,取消未完成的请求
        return () => cancelToken.cancel('请求已取消');
    }, [link]); // 依赖改为link,只有link变化时才重新发起请求

    return [data, loading];
};

第二步:正确使用钩子(同步生成modifiedLink场景)

不需要把钩子放到useEffect里,直接在组件顶层调用,传入处理后的modifiedLink即可。只要modifiedLink发生变化,钩子会自动重新请求:

export const App = () => {
    const link = '/helloworld';
    // 假设getModifiedLink是纯函数,基于link生成新的链接
    const modifiedLink = getModifiedLink(link);

    // 直接在组件顶层调用钩子
    const [data, loading] = useGetApi(modifiedLink);

    // 根据状态渲染UI
    if (loading) return <div>加载中...</div>;
    return <div>{JSON.stringify(data)}</div>;
};

第三步:异步生成modifiedLink场景的处理

如果modifiedLink需要通过异步操作生成(比如先请求其他接口获取参数),可以用状态存储最终的链接,再传给钩子:

export const App = () => {
    const [finalLink, setFinalLink] = useState(null);
    const baseLink = '/helloworld';

    // 异步获取并生成最终链接
    useEffect(() => {
        const generateFinalLink = async () => {
            // 模拟异步获取参数
            const params = await fetchRequiredParams();
            const modified = `${baseLink}?${new URLSearchParams(params)}`;
            setFinalLink(modified);
        };
        generateFinalLink();
    }, [baseLink]);

    // 只有finalLink存在时才发起请求
    const [data, loading] = useGetApi(finalLink);

    if (!finalLink) return <div>准备请求中...</div>;
    if (loading) return <div>加载中...</div>;
    return <div>{JSON.stringify(data)}</div>;
};

这样既复用了原有的useGetApi钩子,又解决了不同场景下的链接处理需求,完全不需要新增重复代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 10:40:36