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

React+TypeScript中useSend函数为何返回void?

问题原因与修复方案

问题一:违反React Hook调用规则

你把useSend命名为use开头的函数,这会被React识别为自定义Hook,但自定义Hook只能在组件函数顶层或其他自定义Hook顶层调用,绝对不能在事件处理函数、循环、条件判断里调用。

你在useSubmit这个表单事件处理函数里调用useSend,完全违反了Hook的调用规则,导致React无法正确追踪Hook的执行上下文,最终使得useSend返回undefined,后续调用.then()自然会抛出Cannot read properties of undefined (reading 'then')的错误。

问题二:Promise链逻辑断裂

即便修复了Hook调用问题,useSend内部的Promise链也有漏洞:在非200状态的分支中,你调用了response.json().then(...)但没有return这个Promise,导致该分支的then回调默认返回undefined,使得整个Promise链的最终值不符合你声明的Promise<string>类型约定,同时逻辑上也无法传递错误响应的内容。


修复方案

1. 修正函数定位与命名

如果useSend只是普通的HTTP请求工具函数(没有用到React的任何Hook),直接去掉use前缀,比如改名为sendRequest,这样就能在事件处理函数里正常调用:

const sendRequest = (method: string, url: string, data: any): Promise<string | any> => {
    return fetch(url, {
        method: method,
        headers: { 
            "Content-Type": "application/json",
            "Accept": "application/json", 
        },
        credentials: 'include',
        body: JSON.stringify(data),
    })
    .then((response) => {  
        if (response.status === 200) {
            return "success";
        } else {
            // 必须return这个Promise,保证链不中断
            return response.json();
        }
    })
    .catch(err => {
        console.log(err);
        return err;
    });
}

export default sendRequest;

2. 修复调用代码

在useSubmit里调用重命名后的工具函数,同时补上类型断言和错误分支处理:

function useSubmit (event: React.FormEvent<HTMLFormElement>) {
    event.preventDefault();
    const form = new FormData(event.currentTarget);
    const data = { 
        email: form.get('email') as string, 
        password: form.get('password') as string 
    };
    
    sendRequest("POST", "http://localhost:2999/login", data)
        .then((temp) => {
            console.log(temp);
            if (temp === "success") {
                window.location.href = "/feed/latest";
            } else {
                console.error("登录失败:", temp);
                // 这里可以加用户提示,比如弹出错误信息
            }
        })
        .catch(err => {
            console.error("请求出错:", err);
        });
}

额外优化:用async/await简化逻辑

把sendRequest改成async函数,代码可读性更高:

const sendRequest = async (method: string, url: string, data: any): Promise<string | any> => {
    try {
        const response = await fetch(url, {
            method: method,
            headers: { 
                "Content-Type": "application/json",
                "Accept": "application/json", 
            },
            credentials: 'include',
            body: JSON.stringify(data),
        });
        if (response.status === 200) {
            return "success";
        } else {
            return await response.json();
        }
    } catch (err) {
        console.log(err);
        return err;
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 20:33:35