React useEffect Hook首次加载后偶发不调用API、状态未设置报错问题
报错原因
你的报错本质不是useEffect没有调用API,是组件首次渲染时data初始值为null,你在<img>标签的src属性中直接访问data.volumeInfo,没有做非空判断,导致API请求还没返回结果,组件就因为空值访问直接渲染崩溃,所以看起来像是API没调用成功。
另外还有几个隐性问题:
- 异步逻辑写法错误:你声明了
async函数但没有搭配await使用,try/catch完全无法捕获fetch的请求报错 - HTML结构不规范:重复嵌套了多个
<body>标签,可能引发额外的渲染异常
完整修复代码
import '../App.css'; import Navigation from './Navigation'; import React, { useState, useEffect } from 'react'; import { NavLink } from 'react-router-dom'; const Milestone1 = () => { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { const callAPI = async () => { try { const res = await fetch("https://www.googleapis.com/books/v1/volumes/Wfan6L9RGgYC"); const result = await res.json(); setData(result); setLoading(false); } catch (e) { console.log(e); setError(e); setLoading(false); } }; callAPI(); }, []); // 加载中展示提示 if (loading) return <div>加载中...</div>; // 请求出错展示报错 if (error) return <div>请求失败,请刷新重试</div>; // 无数据时展示空提示 if (!data) return <div>暂无数据</div>; return ( <div className="school"> <header className="App-header"> </header> <center> <div className="navigation"> <Navigation /> </div> <div className="App-body"> <h2>Milestone 1</h2> <h5>Title: {data.volumeInfo?.title}</h5> {data.volumeInfo?.imageLinks?.smallThumbnail && ( <img src={data.volumeInfo.imageLinks.smallThumbnail} alt="书籍封面" /> )} <h5> Authors: {data.volumeInfo?.authors} Publish info: {data.volumeInfo?.publisher} {data.volumeInfo?.publishedDate} Country: {data.saleInfo?.country} </h5> <h5>Rating: {data.volumeInfo?.averageRating}</h5> <NavLink to="/Milestone1part2">Milestone 1 part two</NavLink><br/> </div> </center> </div> ); } export default Milestone1;
核心修改点说明
- 修正异步逻辑:用
async/await搭配try/catch正确捕获请求异常,新增加载状态、错误状态处理,避免请求过程中渲染空数据 - 增加非空判断:所有深层属性访问都用可选链
?.做判空,图片渲染前先判断资源地址是否存在,避免空值报错 - 修正HTML结构:删掉重复嵌套的
<body>标签,用普通div包裹内容,符合HTML规范 - 新增前置渲染拦截:加载完成、请求成功前不渲染业务内容,从根源避免空值访问问题
简化版Hook逻辑
const [data, setData] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { const fetchData = async () => { const res = await fetch("https://www.googleapis.com/books/v1/volumes/Wfan6L9RGgYC"); const result = await res.json(); setData(result); setLoading(false); }; fetchData(); }, []);
内容的提问来源于stack exchange,提问作者gatorade2131
相关产品推荐
相关产品推荐

