React中useEffect与Affinda API交互异常:先输出空数组再获正确数据
问题原因及解决办法
核心问题分析
你这段代码的问题主要出在三个地方:
- 违反React钩子规则:把
useState、useEffect直接放在普通函数fetchCvList里——React钩子只能在函数组件顶层或者以use开头的自定义钩子中使用,这种错误用法会导致状态管理混乱,触发多次不必要的执行,也就是你看到的两次空数组输出。 - 异步代码执行顺序:
console.log(user)是同步代码,函数执行时立刻就会运行;而useEffect里的接口请求是异步操作,要等组件渲染(或错误函数执行)完成后才触发,请求结束后才会更新user状态,此时同步的console.log早就执行完了,所以先输出空数组,后出正确数据。 - 冗余写法:同时使用
await和.then,属于没必要的混用,会让代码逻辑更混乱。
修正后的代码(符合React规则的自定义钩子方案)
import {AffindaCredential, AffindaAPI} from "@affinda/affinda"; import { useEffect, useState } from "react"; const credential = new AffindaCredential("") const client = new AffindaAPI(credential) // 自定义钩子必须以use开头,符合React钩子规则 export function useFetchCvList() { const [user, setUser] = useState<any>([]) const [loading, setLoading] = useState(true) const [error, setError] = useState<Error | null>(null) useEffect(() => { const fetchData = async () => { try { // 去掉冗余的.then,只用await处理异步逻辑 const result = await client.getResume("grLaMgEb") if(result){ setUser(result.data) } } catch (err) { console.log("An error occurred:"); console.error(err); setError(err as Error) } finally { setLoading(false) } } fetchData() }, []) // 返回数据、加载状态、错误信息给组件使用 return { user, loading, error } }
在组件中使用自定义钩子
function CvListComponent() { const { user, loading, error } = useFetchCvList() // 根据状态处理UI显示 if(loading) return <div>加载中...</div> if(error) return <div>加载失败:{error.message}</div> // 这里的console.log会在状态更新后触发组件重新渲染,输出正确数据 console.log(user) return <div>{JSON.stringify(user)}</div> }
为什么会输出两次空数组?
因为你在普通函数里使用钩子,React的钩子检测机制会判定这是非法用法,触发异常的重新执行,导致fetchCvList被调用两次,每次调用都会初始化user为空数组并执行同步的console.log,所以会看到两次空数组。当异步请求完成更新状态后,原函数不是组件/自定义钩子,状态更新不会触发它重新执行;而修正后的自定义钩子会在状态更新时触发组件重新渲染,从而输出正确数据。
内容的提问来源于stack exchange,提问作者Paweł Ciszewski
相关产品推荐
相关产品推荐

