React页面刷新后fetch请求失效 报Cannot read properties of undefined错误
问题现象
通过axios发起请求获取单个对象数据时,页面首次加载偶发可以正常渲染接口字段,刷新页面后无法正常渲染数据,控制台抛出错误:
Uncaught TypeError: Cannot read properties of undefined (reading 'name')
报错参考截图:
对应问题代码:
import { useState, useEffect } from "react"; import axios from "axios"; function DataFetching() { const [products, setProducts] = useState([]); useEffect(() => { const loadProducts = async () => { const response = await axios.get("https://CENSORED/"); setProducts(response.data); }; loadProducts(); }, []); return ( <> <div className="App"> <p>{products.product.name}</p> </div> </> ); }
问题根因
- 异步请求时序逻辑问题:
useEffect的回调会在组件完成首次挂载渲染后才执行,组件第一次render阶段,products还是手动设置的初始值空数组[],此时直接访问products.product.name,相当于在空数组上读取不存在的product属性(值为undefined),再读取undefined上的name字段,直接触发类型错误。 - 初始值类型不匹配:接口返回的是包含
product字段的对象结构,但初始值设置为空数组,和接口返回结构完全不一致,放大了渲染阶段的类型错误。 - 首次加载正常属于偶发场景:一般是本地开发热更新缓存、接口响应速度极快刚好在首屏渲染前完成状态赋值导致的,刷新页面走完整的「组件挂载→首屏渲染→执行effect发请求」流程,问题就会稳定复现。
修复方案
方案1:可选链安全访问(改动最小)
修正初始值类型和接口返回结构对齐,同时用可选链操作符?.做属性访问兜底,链路中某段属性不存在时直接返回undefined,不会抛出错误:
import { useState, useEffect } from "react"; import axios from "axios"; function DataFetching() { // 初始值改为空对象,和接口返回的对象结构对齐 const [products, setProducts] = useState({}); useEffect(() => { const loadProducts = async () => { const response = await axios.get("https://CENSORED/"); setProducts(response.data); }; loadProducts(); }, []); return ( <> <div className="App"> {/* 可选链做访问兜底,数据未返回时不报错 */} <p>{products?.product?.name}</p> </div> </> ); }
方案2:增加加载状态(生产环境推荐)
增加loading状态控制渲染逻辑,请求未完成时显示加载占位,等数据就绪后再渲染对应字段,同时补充错误处理逻辑,用户体验更好:
import { useState, useEffect } from "react"; import axios from "axios"; function DataFetching() { const [products, setProducts] = useState({}); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { const loadProducts = async () => { try { const response = await axios.get("https://CENSORED/"); setProducts(response.data); } catch (err) { setError("数据加载失败,请稍后重试"); } finally { setLoading(false); } }; loadProducts(); }, []); if (loading) return <div className="App">数据加载中...</div>; if (error) return <div className="App">{error}</div>; return ( <> <div className="App"> <p>{products.product.name}</p> </div> </> ); }
内容的提问来源于stack exchange,提问作者Kikoanno
相关产品推荐
相关产品推荐

