React中如何在state存储复杂JSON对象并渲染对应UI内容
报错根因
组件首次渲染的时机早于接口请求返回时间,你初始state里的excelData是空对象,不存在data属性,直接对undefined调用.map()方法就会抛出类型错误。
你之前把excelData初始值改成数组、接口回调只存response.data.data能跑通列表,是因为数组本身自带map方法,首次渲染遍历空数组不会报错,但这种写法把excelData变成了纯数组结构,根本存不下接口返回的support、page等同级字段,没法满足多字段渲染的需求,不是正确方案。
正确实现步骤
1. 给state设置和接口结构匹配的初始值
按照接口返回的JSON结构定义初始state,把data初始为空数组、support初始为空对象,既保证首次渲染时调用map不报错,也能完整存储整个接口返回的复杂结构:
state = { excelData: { page: 0, per_page: 6, total: 0, total_pages: 0, data: [], support: {} }, loading: false, error: null }
2. 修正生命周期请求逻辑
注意setState是异步方法,你原来写在axios请求后面的console.log拿不到更新后的state值,需要打印的话要写到setState的回调里,另外补上请求异常捕获:
componentDidMount(){ this.setState({ loading: true }) axios.get('https://reqres.in/api/unknown') .then((response) => { this.setState({ excelData: response.data, loading: false }) // 要打印更新后的值在这里写 // console.log(this.state.excelData) }) .catch(err => { this.setState({ error: err.message, loading: false }) }) }
3. 渲染时增加安全兜底,同时渲染多部分内容
渲染时建议通过可选链做兼容兜底,避免接口返回结构异常时页面崩溃,同时可以分别读取不同字段渲染对应UI:
render(){ const { excelData, loading, error } = this.state if(loading) return <div>数据加载中...</div> if(error) return <div>加载失败:{error}</div> return ( <div> {/* 渲染分页字段 */} <div className="page-info"> <p>当前第{excelData.page}页,共{excelData.total_pages}页,总计{excelData.total}条数据</p> </div> {/* 渲染data数组列表 */} <ListGroup> { excelData.data?.map(item => ( <ListGroupItem key={item.id}> <span style={{color: item.color}}>名称:{item.name}</span> <span style={{marginLeft: '16px'}}>发布年份:{item.year}</span> <span style={{marginLeft: '16px'}}>潘通色号:{item.pantone_value}</span> </ListGroupItem> )) } </ListGroup> {/* 渲染support对象内容 */} <div className="support-tip" style={{marginTop: '24px', padding: '12px', background: '#f5f5f5', borderRadius: '4px'}}> <p>{excelData.support?.text}</p> </div> </div> ) }
额外注意点
- 你当前代码里导入了
useState和useEffect但没有使用,这两个是函数组件专属的Hook,类组件场景下可以直接删除这两个导入,减少无用代码。 - 类组件的
setState会自动合并顶层state属性,更新excelData这类独立字段时,不需要手动展开旧的this.state,直接赋值新值即可。 - 可选链操作符
?.是ES2020标准语法,Create React App 3及以上版本默认支持。如果你的项目构建版本较老不支持该语法,可以换成(excelData.data || []).map()的写法做兜底,效果完全一致。
内容的提问来源于stack exchange,提问作者user1890098
相关产品推荐
相关产品推荐

