React条件渲染展示接口数据时出现空白页及非法子节点报错
问题描述
在React中实现条件渲染逻辑:接口数据未拉取完成时展示"Loading"加载提示,数据拉取完成后展示服务端返回的JSON响应数据。实际运行时页面空白:将数据加载成功分支的渲染内容替换为纯文本时页面可正常展示,替换为接口返回的实际数据时触发异常,呈现空白页。
问题复现代码
import { useState, useEffect } from 'react' function changeFeed(bookData){ let elem; if (Object.keys(bookData).length === 0) elem = <p>Loading</p> else elem = <p>{bookData}</p> return elem; } export default function Feed() { const [bookData, setBookData] = useState({}); useEffect(() => { fetch('/book') .then(res => res.json()) .then(data => setBookData(data)) .catch(err => console.error("Custom err: ",err)) }, []); return ( <div> {changeFeed(bookData)} </div> ) }
运行报错信息
核心报错:
Uncaught Error: Objects are not valid as a React child (found: object with keys {data}). If you meant to render a collection of children, use an array instead.
完整错误栈:
Uncaught Error: Objects are not valid as a React child (found: object with keys {data}). If you meant to render a collection of children, use an array instead. at throwOnInvalidObjectType (react-dom.development.js:14757:1) at reconcileChildFibers (react-dom.development.js:15698:1) at reconcileChildren (react-dom.development.js:19971:1) at updateHostComponent$1 (react-dom.development.js:20733:1) at beginWork (react-dom.development.js:22447:1) at HTMLUnknownElement.callCallback (react-dom.development.js:4161:1) at Object.invokeGuardedCallbackDev (react-dom.development.js:4210:1) at invokeGuardedCallback (react-dom.development.js:4274:1) at beginWork$1 (react-dom.development.js:27405:1) at performUnitOfWork (react-dom.development.js:26513:1) react-dom.development.js:18572 The above error occurred in the <p> component: at p at div at Feed (http://localhost:3000/static/js/bundle.js:129:82) at div at http://localhost:3000/static/js/bundle.js:1449:66 at Grid (http://localhost:3000/static/js/bundle.js:8640:87) at div at http://localhost:3000/static/js/bundle.js:1449:66 at Grid (http://localhost:3000/static/js/bundle.js:8640:87) at div at http://localhost:3000/static/js/bundle.js:1449:66 at Box (http://localhost:3000/static/js/bundle.js:19329:72) at Home at InnerThemeProvider (http://localhost:3000/static/js/bundle.js:18542:70) at ThemeProvider (http://localhost:3000/static/js/bundle.js:18199:5) at ThemeProvider (http://localhost:3000/static/js/bundle.js:18562:5) at App Consider adding an error boundary to your tree to customize error handling behavior. logCapturedError @ react-dom.development.js:18572 react-dom.development.js:26874 Uncaught Error: Objects are not valid as a React child (found: object with keys {data}). If you meant to render a collection of children, use an array instead. at throwOnInvalidObjectType (react-dom.development.js:14757:1) at reconcileChildFibers (react-dom.development.js:15698:1) at reconcileChildren (react-dom.development.js:19971:1) at updateHostComponent$1 (react-dom.development.js:20733:1) at beginWork (react-dom.development.js:22447:1) at beginWork$1 (react-dom.development.js:27381:1) at performUnitOfWork (react-dom.development.js:26513:1) at workLoopSync (react-dom.development.js:26422:1) at renderRootSync (react-dom.development.js:26390:1) at recoverFromConcurrentError (react-dom.development.js:25806:1) manifest.json:1 Manifest: Line: 1, column:1, Syntax error.
注:末尾的manifest.json语法错误是项目PWA配置文件问题,和本次白屏的渲染错误无关
接口返回数据结构
接口返回书籍对象数组,示例结构:
[ {_id: '628a333def2ed59e884896b2', title: 'everything need to be known', author_id: '6281de055717560ea372c656', summary: 'Summary need to be updated plz check after sometime', isbn: '69-ass-69'}, {_id: '628a39263e2377b56cb55a28', title: 'everyhton needto knpe', author_id: '6281de055717560ea372c656', summary: 'Summary need to be updated plz check after sometime', isbn: '159'}, {_id: '628a3a2a66c6bb5f9c8d39c3', title: 'jkejvnskre vkn', author_id: '6281de055717560ea372c656', summary: 'Summary need to be updated plz check after sometime', isbn: 'lkrmvle'}, {_id: '628a3aa53de4e9fa6f4a6124', title: 'jcnj jflkl kK', author_id: '6281de055717560ea372c656', summary: 'Summary need to be updated plz check after sometime', isbn: 'lck lsdk'}, {_id: '628a5bad4c97c8d9a5828dc7', title: 'avrj f,lskfjf', author_id: '6281de055717560ea372c656', summary: 'Summary need to be updated plz check after sometime', isbn: 'lkv skjf '}, {_id: '628a5c4baa89e5d3a93f6398', title: 'k cjdkj,fk;klad', author_id: '6281de055717560ea372c656', summary: 'Summary need to be updated plz check after sometime', isbn: 'klc wjd'} ]
问题原因
- 核心问题:React不支持直接将JavaScript对象、数组作为JSX子元素渲染,只能渲染字符串、数字、合法的React节点、布尔值/null/undefined(这些会被忽略)。代码里数据加载完成后直接把
bookData(接口返回的对象/数组)放到<p>标签内,React无法将普通对象解析为DOM节点,直接抛出渲染异常导致整页白屏。 - 加载判断逻辑有隐患:通过判断空对象的键长度来确认加载状态,一旦接口返回空数组、空对象,会一直停留在Loading状态;报错提示明确说明拿到的对象带
data键,说明接口实际返回结构是{data: 书籍数组}的格式,直接赋值后bookData不是数组,后续遍历也会出问题。
修复方案
- 单独维护
loading状态标记加载过程,不要依赖数据是否为空判断加载状态,避免空数据场景的判断错误。 - 接口返回数据先按实际结构取出需要渲染的数组部分,不要直接渲染整个响应对象。
- 渲染数组时通过
map遍历每一项,将对象的字段拆分为基础类型值(字符串、数字)渲染,不要直接输出整个对象。 - 如果只是临时调试查看接口返回内容,可以用
JSON.stringify(bookData)将对象转为字符串后渲染,不要直接放原始对象。
修复后的可运行代码:
import { useState, useEffect } from 'react' export default function Feed() { const [bookData, setBookData] = useState([]); // 单独维护加载状态 const [loading, setLoading] = useState(true); useEffect(() => { setLoading(true); fetch('/book') .then(res => res.json()) .then(res => { // 兼容两种接口返回结构:直接返回数组 / 返回{data: 数组}格式 setBookData(Array.isArray(res) ? res : res.data || []) }) .catch(err => console.error("Custom err: ", err)) .finally(() => setLoading(false)) }, []); if (loading) return <p>Loading</p> return ( <div> {bookData.map(book => ( <div key={book._id} style={{ marginBottom: '1rem' }}> <h3>{book.title}</h3> <p>ISBN:{book.isbn}</p> <p>摘要:{book.summary}</p> </div> ))} </div> ) }
内容的提问来源于stack exchange,提问作者Fallen
相关产品推荐
相关产品推荐

