React使用Apollo Client解构useQuery结果刷新报undefined错误
报错信息
Uncaught TypeError: Cannot destructure property 'slumpMedias' of '(0 , apollo_client__WEBPACK_IMPORTED_MODULE_4_.useQuery)(...)' as it is undefined.
问题背景
React.js项目采用WordPress + GraphQL作为Headless CMS搭建后端能力,项目配置已校验无误,通过Apollo Client和gql实现GraphQL查询调用。
最后一次可正常运行的代码
import { useQuery } from "@apollo/client"; import gql from "graphql-tag"; const GET_ALL_MEDIA = gql` query MyQuery { slumpMedias(first: 100) { edges { node { title slumpMeta { image { mediaItemUrl } audio1 { mediaItemUrl } } } } } } `; function Items() { const { loading, error, data } = useQuery(GET_ALL_MEDIA); console.log(data); if (loading) return <h1>Loading..</h1>; if (error) return <h1>Loading..</h1>; return <div>Hello</div>; }
该版本运行时控制台打印的data结构正常,可成功获取数据:
>slumpMedias: {…}} >slumpMedias: >edges: (17) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}] >[[Prototype]]: Object >[[Prototype]]: Object
问题现象
接口调用验证通过后,为简化后续数据调用逻辑,对返回对象做深层解构,调整后的查询代码如下:
const { loading, error, data: { slumpMedias: { edges }, }, } = useQuery(GET_ALL_MEDIA); console.log(edges);
代码保存后浏览器热更新自动加载页面,控制台可正常打印预期的edges数组,包含17条数据:
(17) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
但手动刷新页面时,项目提示编译成功,页面完全白屏,抛出如下错误栈:
Items.js:34 Uncaught TypeError: Cannot destructure property 'slumpMedias' of '(0 , _apollo_client__WEBPACK_IMPORTED_MODULE_4__.useQuery)(...)' as it is undefined. at Items (Items.js:34:1) at renderWithHooks (react-dom.development.js:16175:1) at mountIndeterminateComponent (react-dom.development.js:20913:1) at beginWork (react-dom.development.js:22416: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) at workLoopSync (react-dom.development.js:26422:1)
已确认graphql-tag依赖引入正确,问题仍未解决。
根本原因
报错核心原因是组件首次渲染时请求未完成,data字段为undefined:
- Apollo Client的
useQuery钩子在请求初始阶段、数据未返回时,返回值中的data字段默认是undefined。 - 热更新场景下能正常运行,是因为热更新触发时上一次请求的结果已经存在于Apollo缓存中,组件重渲染时直接读取缓存数据,不会出现
data为undefined的情况。 - 手动刷新页面时缓存被清空,组件首次渲染时请求处于pending状态,
data为undefined,此时直接深层解构data: { slumpMedias: { edges } },等价于尝试从undefined上读取slumpMedias属性,直接抛出类型错误,中断组件渲染导致白屏。 - 初始版本代码不报错,是因为初始版本仅解构第一层的
loading/error/data,没有在解构阶段直接读取data内部属性,等loading判断通过、数据返回后才操作data,不会触发解构错误。
修复方案
方案1:解构时设置默认值(改动最小)
给深层解构的层级设置空对象默认值,避免undefined解构报错:
const { loading, error, data: { slumpMedias: { edges } = {}, } = {}, } = useQuery(GET_ALL_MEDIA);
加载阶段edges值为undefined,配合原有的loading/error判断逻辑即可正常运行,不会打断渲染。
方案2:分层处理(逻辑更清晰,更推荐)
先解构第一层返回值,等加载、错误状态校验通过、确认data存在后,再解构内部属性:
function Items() { const { loading, error, data } = useQuery(GET_ALL_MEDIA); if (loading) return <h1>Loading..</h1>; if (error) return <h1>Load failed</h1>; // 逻辑走到此处时data一定存在,解构不会报错 const { slumpMedias: { edges } } = data; console.log(edges); return <div>Hello</div>; }
内容的提问来源于stack exchange,提问作者Kevin
相关产品推荐
相关产品推荐

