React组件如何等待API请求完成后再渲染内容
问题分析与优化方案
首先你的代码存在几个关键问题:
FetchWithKeyw的初始状态设为字符串'',但接口返回的是数组,导致首次渲染时latestdatas[0]直接是undefineduseEffect的依赖数组为空,且then/catch里错误地加了[],这会导致keyw变化时不会重新发起请求- 组件直接访问
latestdatas[0].Title这类属性,没有做任何空值判断,必然会在请求未完成时报错
以下是几种更优的处理方案:
方案一:优化自定义Hook(推荐)
把Hook改成返回数据、加载状态、错误状态的结构,同时修正初始状态和依赖项,让组件能更清晰地处理不同状态:
export function FetchWithKeyw(keyw){ // 初始状态设为空数组,和接口返回类型一致 const [data, setData] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { // 每次请求前重置状态 setLoading(true); setError(null); axios.get(`************:8000/${keyw}`) .then(res => { setData(res.data); }) .catch(err => { console.log(err); setError(err); }) .finally(() => { setLoading(false); }); }, [keyw]); // 依赖keyw,参数变化时重新请求 return { data, loading, error }; }
组件中使用:
function Aboutus(props) { const { data: latestdatas, loading, error } = FetchWithKeyw("car"); // 加载中状态处理 if (loading) { return <LoadingTransition />; // 或者简单返回<div>加载中...</div> } // 错误状态处理 if (error) { return <div>加载失败:{error.message}</div>; } // 数据为空时的兜底 if (!latestdatas.length) { return <div>暂无数据</div>; } return( // ...其他内容 <PreviewDataset image="/420X358-7.jpg" title={latestdatas[0].Title} desc={latestdatas[0].Description} category={latestdatas[0].Indicator_Class} /> // ...其他内容 ) }
方案二:组件内直接做防御性处理(快速修复)
如果不想改动Hook,可在组件内通过可选链操作符和条件渲染避免报错:
function Aboutus(props) { // 先把FetchWithKeyw的初始状态从''改成[],否则字符串没有length属性会报错 const latestdatas = FetchWithKeyw("car"); // 数据未准备好时显示加载态 if (!latestdatas.length) { return <LoadingTransition />; } return( // ...其他内容 <PreviewDataset image="/420X358-7.jpg" // 用可选链访问,避免undefined报错 title={latestdatas[0]?.Title} desc={latestdatas[0]?.Description} category={latestdatas[0]?.Indicator_Class} /> // ...其他内容 ) }
方案三:给PreviewDataset组件添加默认属性
如果PreviewDataset是你自己维护的组件,可以给它的props设置默认值,即使传入undefined也不会报错:
function PreviewDataset({ image, title = '', desc = '', category = '' }) { return ( // 组件内容 ) }
结合可选链一起使用,体验会更好。
内容的提问来源于stack exchange,提问作者kostaskrav
相关产品推荐
相关产品推荐

