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
相关产品推荐
相关产品推荐

