GraphQL查询结果嵌入Object崩溃、嵌入JSX正常的问题排查
问题根因
useQuery 是异步执行的Hook,组件首次渲染时GraphQL请求还在发送阶段,此时返回的data初始值为undefined。你在组件顶层同步定义objects数组时直接读取data.slumpMedias,等价于执行undefined.slumpMedias,直接抛出类型错误中断React渲染流程,导致白屏。
你之前把路径写在JSX里看似能正常运行,是因为开发环境热更新、Apollo本地缓存命中时,组件首次渲染就能拿到缓存的旧数据,没有触发
data为undefined的初始状态;硬刷新页面后缓存被清空,首次渲染必然进入loading状态,就稳定复现报错。你观察到的「短暂渲染正确内容」是请求返回后触发重渲染的预期结果,但首次渲染的报错已经让整个组件树崩溃,重渲染逻辑根本没有机会执行。
修复方法
- 必须先处理请求的loading、error状态,在请求未完成、请求出错时不要访问data下的任何字段
- 确认data存在后再构建自定义数据结构,不要在组件顶层无任何判断就直接访问data的深层属性
修复后的可运行代码:
function Items() { const { loading, error, data } = useQuery(GET_ALL_MEDIA); // 加载状态返回占位 if (loading) return <div>内容加载中</div>; // 请求异常返回错误提示 if (error) return <div>加载失败:{error.message}</div>; // 执行到此处时data已完成赋值,可安全读取字段 const objects = [ { id: 0, title: data.slumpMedias.edges[6].node.title, image: "/images/1.png", sound: "/default-sound.mp3", items: [], }, ]; return <Display objects={objects} />; }
如果不想提前中断渲染,也可以用可选链+空值兜底避免读取undefined属性:
function Items() { const { loading, error, data } = useQuery(GET_ALL_MEDIA); // data不存在时objects默认为空数组 const objects = data?.slumpMedias ? [ { id: 0, title: data.slumpMedias.edges[6].node.title, image: "/images/1.png", sound: "/default-sound.mp3", items: [], }, ] : []; if (loading) return <div>内容加载中</div>; if (error) return <div>加载失败:{error.message}</div>; return <Display objects={objects} />; }
注意:你最开始写的直接在JSX中读取data.slumpMedias.edges[5].node.title的代码本身也存在同样的隐患,只是之前缓存命中没触发报错,同样需要加状态判断或者可选链兜底,否则清空缓存硬刷新时一样会崩溃。
内容的提问来源于stack exchange,提问作者Kevin
相关产品推荐
相关产品推荐

