React组件读取this.state中JSON对象时出现'DV'未定义错误
解决React类组件中访问嵌套state属性时的Undefined错误
这个问题我之前也踩过坑,本质是组件初始渲染时异步数据还没加载完成,导致你尝试访问还未存在的嵌套属性,触发了Cannot read property 'DV' of undefined错误。咱们一步步来拆解原因和解决办法:
为什么会报错?
你的组件执行流程是这样的:
- 组件初始化,
state是一个空对象{} - 立刻执行
render()方法,这时候this.state.SiteRep是undefined,你直接访问this.state.SiteRep.DV自然会报错 - 之后
componentDidMount才会触发,发起异步fetch请求,请求完成后通过setState更新state,这时候组件才会重新渲染,此时this.state.SiteRep才存在
三种可行的解决方案
方案1:初始化state时设置默认结构
给state设置一个和返回数据结构匹配的默认值,让初始渲染时嵌套属性不会是undefined:
class App extends Component { // 初始化时给SiteRep和DV设置默认空结构 state = { SiteRep: { DV: {} } } componentDidMount() { const url = 'http://datapoint.metoffice.gov.uk/public/data/val/wxfcs/all/json/APIKEY' fetch(url) .then(response => response.json()) .then(data => { this.setState(data) }) } render() { // 现在初始渲染时不会报错,数据加载后会自动更新 console.log(this.state.SiteRep.DV) return <p>TEXT</p> } } export default App
方案2:在render中添加条件判断(推荐)
在访问嵌套属性前,先判断父级属性是否存在,可以用可选链操作符(?.)(ES2020+支持),或者逻辑与&&做短路判断:
class App extends Component { state = {} componentDidMount() { const url = 'http://datapoint.metoffice.gov.uk/public/data/val/wxfcs/all/json/APIKEY' fetch(url) .then(response => response.json()) .then(data => { this.setState(data) }) } render() { // 用可选链操作符,只要链上任意属性不存在就返回undefined,不会报错 console.log(this.state.SiteRep?.DV) // 或者用逻辑与做短路判断 // console.log(this.state.SiteRep && this.state.SiteRep.DV) // 如果要渲染Period列表,也可以先判断是否存在再映射 const periods = this.state.SiteRep?.DV?.Period || [] return ( <div> {periods.map(period => ( <div key={period.value}>{period.value}</div> ))} </div> ) } } export default App
方案3:添加加载状态提示
如果想给用户更友好的反馈,可以在state中加一个加载状态,数据加载完成前显示加载提示:
class App extends Component { state = { isLoading: true, SiteRep: {} } componentDidMount() { const url = 'http://datapoint.metoffice.gov.uk/public/data/val/wxfcs/all/json/APIKEY' fetch(url) .then(response => response.json()) .then(data => { this.setState({ ...data, isLoading: false }) }) // 别忘了处理请求失败的情况 .catch(err => { console.error('请求失败:', err) this.setState({isLoading: false}) }) } render() { if (this.state.isLoading) { return <p>加载中...</p> } // 数据加载完成后再访问嵌套属性 console.log(this.state.SiteRep.DV) const periods = this.state.SiteRep.DV?.Period || [] return ( <div> {periods.map(period => ( <div key={period.value}>{period.value}</div> ))} </div> ) } } export default App
内容的提问来源于stack exchange,提问作者user12189582
相关产品推荐
相关产品推荐

