React依赖数组报错,Post方法失效,useCallback依赖问题求助
修复useHttp自定义Hook的依赖警告与功能问题
原代码存在的核心问题
- init对象重复创建导致依赖失效:组件每次渲染时,
init都会被重新声明为新对象,导致useCallback的依赖数组变化,触发http函数反复重建,进而让useEffect重复执行。 - 渲染阶段调用setBody引发无限循环:直接在函数体中调用
setBody会触发状态更新,导致组件反复渲染,陷入循环。 - fetch参数格式错误:fetch的第二个参数是配置对象,原代码错误地将body单独作为参数传入。
- Get/Post逻辑未区分处理:Get请求不需要发送body,原代码未做区分,可能导致无效请求。
修复后的完整代码
import { useCallback, useEffect, useState, useMemo } from 'react' const useHttp = (url) => { const [data, setData] = useState(null); const [error, setError] = useState(null); const [loading, setLoading] = useState(true); const [method, setMethod] = useState('get'); const [requestBody, setRequestBody] = useState(null); // 用useMemo缓存init,仅当method变化时重新生成 const init = useMemo(() => ({ method: method.toLowerCase(), headers: { "Content-Type": "application/json" } }), [method]); const http = useCallback(async () => { // 重置请求状态 setLoading(true); setError(null); setData(null); try { const fetchOptions = { ...init }; // 非GET请求且存在body时,才添加序列化后的body if (method.toLowerCase() !== 'get' && requestBody) { fetchOptions.body = JSON.stringify(requestBody); } const res = await fetch(url, fetchOptions); if (!res.ok) { throw new Error("Ops! There was an error. Check connection or report to Admin"); } const responseData = await res.json(); setData(responseData); } catch (err) { setError(err.message); } finally { setLoading(false); } }, [url, init, method, requestBody]); useEffect(() => { http(); }, [http]); return { data, error, loading, setRequestBody, setMethod }; } export default useHttp;
关键修复说明
- 用useMemo缓存init对象:将
init的创建逻辑包裹在useMemo中,依赖仅为method,确保只有请求方法变化时才重新生成init,解决useCallback的依赖警告。 - 移除渲染阶段的状态更新:把body的序列化逻辑移到
http函数内部,仅在发起请求时处理,彻底避免无限循环。同时重命名状态为requestBody,避免与fetch的body参数混淆。 - 修正fetch调用格式:将body合并到fetch的配置对象中,严格遵循fetch API的参数要求。
- 区分Get/Post请求:Get请求自动跳过body设置,符合HTTP规范;Post请求则自动序列化传入的requestBody。
- 优化异步逻辑:改用
async/await替代then/catch链,代码更易读,同时修复原代码中未解析响应数据的问题。 - 请求前重置状态:每次发起请求前重置loading、error和data,避免上次请求的状态残留影响当前请求。
内容的提问来源于stack exchange,提问作者davR7
相关产品推荐
相关产品推荐

