React应用刷新页面后渲染接口数据时应用崩溃怎么办
问题背景
- 开发项目为带主题切换功能的REST Countries API前端练习项目
- 路由实现基于react-router-dom:点击国家列表项后跳转至
/countryName路径匹配的国家详情页 - 详情页数据获取逻辑:通过
useLocation钩子读取当前URL,拆分路径得到国家名称参数,再通过axios请求接口获取对应国家的详情数据 - 故障表现:从列表页首次进入详情页功能正常,在详情页执行刷新操作后应用直接崩溃无法渲染,代码中
console.log(country[0].name.common)语句在刷新后返回undefined,触发运行时错误
故障代码如下:
import axios from 'axios' import React,{ useEffect,useState } from 'react' import { useNavigate, useLocation } from 'react-router-dom' const Country = () => { const location = useLocation() const name = location.pathname.split('/')[1] const navigate = useNavigate() const [country,setCountry] = useState({}) useEffect(() => { const getCountry = async() => { try { const res = await axios.get(`https://restcountries.com/v3.1/name/${name.toLowerCase()}?fullText=true`) console.log(res.data,res) setCountry(res.data) } catch (error) { console.log(error) } } getCountry() }, [name]) console.log(country[0].name.common) // 刷新后返回undefined const backButton = (event) => { event.preventDefault() navigate('/') } return ( <div className='country-page page'> <button onClick={backButton} className='backButton'>back button</button> <div className='country-page-layout'> <h2></h2> </div> </div> ) } export default Country
故障原因
- 状态初始值类型不匹配:REST Countries API的name接口返回值为数组类型,但代码中
country状态的初始值设置为空对象{}。组件首次渲染时,useEffect内的异步请求尚未返回结果,country仍为初始空对象,此时访问country[0]得到undefined,继续读取.name.common属性会直接触发类型错误,导致页面崩溃。 - 刷新触发全量重挂载:从列表页跳转进入详情页时无报错,是因为跳转过程的状态更新时序恰好避开了首次渲染的空值访问;刷新页面时前端内存存储的所有状态会被清空,组件完全按照初始值重新挂载渲染,必然触发空值访问错误。
修复方法
- 将
country状态的初始值修改为空数组[],与接口返回的数据类型保持一致 - 增加加载状态与数据存在性校验:数据请求完成前,不直接访问数组项的嵌套属性,可通过可选链
?.做安全访问,或渲染加载占位内容,避免读取不存在的属性 - 关键修复代码示例:
// 修正初始值类型,新增加载状态 const [country,setCountry] = useState([]) const [loading, setLoading] = useState(true) useEffect(() => { const getCountry = async() => { setLoading(true) try { const res = await axios.get(`https://restcountries.com/v3.1/name/${name.toLowerCase()}?fullText=true`) setCountry(res.data) } catch (error) { console.log(error) } finally { setLoading(false) } } getCountry() }, [name]) // 加载状态渲染占位,属性访问增加可选链防护 if (loading) return <div className="page">加载中...</div> console.log(country[0]?.name?.common)
参考材料
- 错误信息截图:

- 项目使用接口为REST Countries API
内容的提问来源于stack exchange,提问作者thefarerevenant
相关产品推荐
相关产品推荐

