Next.js 使用 @apollo/client useQuery 时 data.nodes 偶发 undefined 问题咨询
问题根因和修复方案
被忽略的核心问题
- 代码执行顺序错误
useQuery 首次执行时默认处于 loading 状态,此时data值为undefined。你将data.nodes访问语句放在 loading、error 判断之前,相当于直接操作 undefined 的属性,必然抛出错误。你在控制台看到打印的 data 带有 nodes 属性,是浏览器控制台的引用类型打印延迟特性:你点开打印对象的展开箭头时,查询已经返回数据,但打印执行的那一刻 data 确实是空值。热重载时组件复用了之前已经返回的查询结果,所以小概率能拿到有效值。 - 缺少嵌套属性的兜底处理
哪怕请求完成,也可能存在查询结果结构不符合预期、参数错误返回空结构的场景,直接访问深层属性容易触发报错。 - 潜在的查询参数取值时机问题
如果store.get("ids")是组件渲染后才异步存入的,首次触发 useQuery 时 ids 为空,请求返回的结构自然没有 nodes 属性,后续 ids 变更后如果没有触发重查,也会一直拿不到正确结果。
修复后的代码示例
import { useQuery } from "@apollo/client"; import { Fragment } from "react"; const myComponent = () => { const ids = store.get("ids"); const { loading, error, data } = useQuery(GET_PRODUCTS_BY_ID, { variables: { ids: ids }, // 可选配置:ids为空时不触发无效查询 skip: !ids?.length, }); // 所有data相关操作必须放在loading、error判断之后 if (loading) return <div>Loading...</div>; if (error) return <div>{error.message}</div>; // 用可选链做访问兜底 console.log(data); console.log(data?.nodes); // 遍历前兜底为空数组,避免map时报错 const nodeList = data?.nodes || []; return ( <Fragment> {nodeList.map(node => ( <div key={node.id}>{/* 你的业务渲染逻辑 */}</div> ))} </Fragment> ); }; export default myComponent;
额外校验点
- 确认
GET_PRODUCTS_BY_ID的查询语句里显式声明了返回nodes字段,GraphQL 只会返回你手动指定的字段,漏写的话接口不会返回该属性 - 如果ids是异步更新的,建议把ids存入组件state,更新state触发组件重渲染,自动触发useQuery重新查询
内容的提问来源于stack exchange,提问作者CodingBrah
相关产品推荐
相关产品推荐

