React自定义fetch post Hook请求成功后无法将数据存入state问题
问题原因及修复方案
核心问题原因
- React的状态更新是异步批量执行的,调用
setRespuestaAPI之后,当前渲染闭包内的respuestaAPI仍然是更新前的旧值,需要等到组件触发重渲染之后才能拿到最新状态,所以你在set之后立刻打印会拿到空的初始值。 - 表单侧调用
fetchData时没有加await,请求还没执行完成就打印respuestaAPI,此时状态还没更新,自然为空。 - 原有判断逻辑
if ("status")存在语法错误,非空字符串的布尔值永远为true,无论接口是否请求成功都会走成功分支。 useCallback依赖中直接写JSON.stringify(body)会导致不必要的函数重新生成,对象属性顺序变化就会触发依赖更新。
修复方案
自定义Hook修复
调整参数结构,将请求body改为fetchData的入参,同时增加错误捕获、直接返回请求结果方便调用方使用:
import { useState, useCallback } from 'react'; export default function useFetchPost(path) { const [respuestaAPI, setRespuestaAPI] = useState({}); const [status, setStatus] = useState(false); const [pending, setPending] = useState(false); const fetchData = useCallback(async (body) => { const payload = { method: "POST", headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) }; setPending(true); try { const response = await fetch("http://localhost:8080" + path, payload); const datos = await response.json(); setRespuestaAPI(datos); const reqStatus = response.ok; setStatus(reqStatus); setPending(false); // 直接返回请求结果和状态,不用等状态更新就能拿到数据 return { datos, status: reqStatus }; } catch (err) { setStatus(false); setPending(false); throw err; } }, [path]) return { respuestaAPI, fetchData, pending, status } }
调用侧代码修复
将handleClick改为异步函数,加await等待请求完成,直接拿返回的结果做逻辑判断:
// 调用Hook时仅传入接口路径 const { respuestaAPI, fetchData, pending } = useFetchPost("/usuario"); const handleClick = async () => { const usuario = { nombre: values.username, apellido: values.lastname, email: values.email, password: values.password, ciudad: usuarioEncontrado.ciudad, token: "" } try { // 等待请求完成,拿到返回结果 const { datos, status } = await fetchData(usuario); if (status) { // 存储接口返回的完整用户数据(包含生成的token) window.localStorage.setItem("usuario", JSON.stringify(datos)); handleLogin(true); } else { setErrors({ ...errors, usuarioNoCreado: "Lamentablemente no ha podido registrarse. Por favor intente más tarde" }) } } catch (err) { setErrors({ ...errors, usuarioNoCreado: "网络请求异常,请稍后重试" }) } } // 其他需要使用接口返回数据的场景直接取respuestaAPI即可,状态更新后会自动触发重渲染
补充说明
如果需要在请求完成后,在组件其他位置使用返回的数据,直接读取respuestaAPI即可,请求成功后状态自动更新,所有依赖该状态的组件都会同步拿到最新值。
内容的提问来源于stack exchange,提问作者maropra
相关产品推荐
相关产品推荐

