如何等待useEffect执行完成后再获取自定义Hook返回的有效值
问题根因
React 组件的渲染逻辑是同步执行的,useEffect 会在组件首次渲染完成后才触发执行。因此你封装的自定义 Hook 首次调用时,异步请求还未发起,就会先返回 useState 初始化的空对象;等 useEffect 内的请求完成触发 setData 后,才会触发二次渲染返回真实的数组数据,所以会出现两次打印结果。
修复方案
最通用的实现方式是在自定义 Hook 中新增加载状态标识,调用侧判断加载完成后再使用数据,修改后的代码如下:
- second.js 代码修改
import { useState, useMemo, useEffect } from 'react'; import _ from 'lodash'; // 修正原函数名笔误,和调用侧的 useGetDataArray 对齐 export const useGetDataArray = ({ name, id } = {}) => { // 初始值和返回类型对齐,改为空数组 const [data, setData] = useState([]); // 新增加载状态标记 const [isLoading, setIsLoading] = useState(true); const index = useMemo(() => { console.log("in useMemo"); const client = thirdPartyProvider; return client; }, []); useEffect(() => { console.log("in useEffect"); index .search(name, { numberOfResults: 12, }) .then(res => { setData(_.get(res, "result", [])); }) .finally(() => { // 请求结束后标记加载完成 setIsLoading(false); }) // 补充请求参数name到依赖数组,避免参数变更时不重新请求 }, [index, name]); return { data, isLoading }; };
- first.js 代码修改
const { data: dataArray, isLoading } = useGetDataArray({ name, id }); // 仅在加载完成后使用/打印数据 if (!isLoading) { console.log("Data Array: ", dataArray); }
注意事项
- 不要试图阻塞 React 同步渲染流程等待异步请求返回,这不符合 React 的渲染规则
- 原代码的
useEffect依赖数组漏了请求参数name,会导致name变更时不会重新拉取数据,需要补充到依赖中 - 原自定义 Hook 的函数名存在笔误,少了字母
a,导致调用侧和导出的函数名不匹配,需要修正
内容的提问来源于stack exchange,提问作者MCLarge
相关产品推荐
相关产品推荐

