Next.js自定义useFetch钩子错误状态更新异常求助
自定义useFetch钩子错误处理问题
我为Next.js应用编写了自定义useFetch钩子,代码如下:
import HTTPMethod from "http-method-enum"; import { useState } from "react"; export default function useFetch() { const [data, setData] = useState(null); const [error, setError] = useState(""); const [loading, setLoading] = useState(false); const sendFetch = async (url: string, method: HTTPMethod, body: any): Promise<any> => { try { setLoading(true); const rawResponse = await fetch(url, { method, headers: { Accept: "application/json", "Content-Type": "application/json", }, body: JSON.stringify({ body, }), }); const response = await rawResponse.json(); setData(response); } catch (error: any) { setError(error); } finally { setLoading(false); } }; return [data, loading, error, sendFetch]; }
目前除错误处理外功能正常:当fetch返回400错误码时,Catch块不会触发,所有响应(无论是否为错误)都存入data状态,error状态始终为空。我需要将错误响应存入error状态,且请勿推荐Axios或其他fetch库(边缘环境运行缓慢)。
编辑:
我修改了代码:
import HTTPMethod from "http-method-enum"; import { useState } from "react"; export default function useFetch() { const [data, setData] = useState(null); const [error, setError] = useState(""); const [loading, setLoading] = useState(false); console.log(error) const sendFetch = async (url: string, method: HTTPMethod, body: any): Promise<any> => { try { setLoading(true); const rawResponse = await fetch(url, { method, headers: { Accept: "application/json", "Content-Type": "application/json", }, body: JSON.stringify({ body, }), }); const response = await rawResponse.json(); if (!response.ok) { throw new Error(response.message) } setData(response); } catch (error: any) { setError(error); } finally { setLoading(false); } }; return [data, loading, error, sendFetch]; }
但状态仍未更新:直接传入字符串setError("Error")时能更新状态,但传入catch里的error参数时,error状态还是为空。
解决方案
核心问题分析
- fetch不触发catch的原因:fetch仅在网络层面失败(如断网、域名不存在)时才会抛出错误,HTTP错误码(4xx/5xx)不会自动触发catch。你之前错误检查了解析后的JSON对象的
ok属性,而非原始响应对象的rawResponse.ok(状态码200-299时为true)。 - setError传入error参数不更新的原因:直接存入Error对象可能导致React浅比较无法识别状态变化;另外如果后端返回的错误响应没有
message字段,抛出的Error会是空消息,看起来像状态未更新。
修正后的代码
import HTTPMethod from "http-method-enum"; import { useState } from "react"; export default function useFetch() { const [data, setData] = useState<null | any>(null); const [error, setError] = useState<string>(""); const [loading, setLoading] = useState(false); const sendFetch = async (url: string, method: HTTPMethod, body: any): Promise<void> => { try { setLoading(true); // 重置旧状态,避免干扰新请求 setError(""); setData(null); const rawResponse = await fetch(url, { method, headers: { Accept: "application/json", "Content-Type": "application/json", }, body: body ? JSON.stringify(body) : undefined, // 移除多余的{body}包裹,匹配后端参数格式 }); // 检查原始响应的状态 if (!rawResponse.ok) { let errorMessage = `请求失败:状态码 ${rawResponse.status}`; // 兼容不同格式的错误响应 try { const errorResp = await rawResponse.json(); errorMessage = errorResp.message || errorMessage; } catch (e) { errorMessage = await rawResponse.text() || errorMessage; } throw new Error(errorMessage); } const responseData = await rawResponse.json(); setData(responseData); } catch (err) { // 将Error对象转为字符串存入状态,确保React能识别更新 setError(err instanceof Error ? err.message : String(err)); } finally { setLoading(false); } }; return [data, loading, error, sendFetch] as const; }
关键修复点
- 检查
rawResponse.ok而非解析后的JSON对象,确保HTTP错误码能进入catch块 - 兼容不同格式的错误响应(JSON/纯文本),避免解析失败丢失错误信息
- 请求前重置错误和数据状态,避免旧状态残留
- 将Error对象转为字符串存入
error状态,确保状态更新能被React正确识别 - 修正body传递格式,移除多余的
{body}包裹,匹配后端预期参数结构
内容的提问来源于stack exchange,提问作者Ethan
相关产品推荐
相关产品推荐

