You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

页面启动时useQuery返回data为undefined引发报错如何解决

报错核心原因

你遇到的undefined is not an object和渲染时机无关,是代码逻辑本身的问题:

  1. useQuery是异步请求,组件首次挂载、useEffect执行时,请求还没返回,此时allFeedData的值为undefined,你直接读取allFeedData.seeAllFeedOrder属于访问undefined上的属性,会直接抛错。
  2. allFeedRefetch()是异步方法,你调用后没有等待请求返回就立刻读取allFeedData,此时拿到的还是请求未完成的undefined值。
  3. 你的useEffect依赖是空数组,只会在组件挂载时执行一次,就算后续请求返回、allFeedData更新了,排序和赋值逻辑也不会再重新执行,最终存入state的数据永远是首次执行时的错误值。
  4. 额外用useState存排序后的数据属于冗余状态,很容易出现源数据和派生数据不同步的问题。
修复方案

不需要额外用useEffect监听、也不需要单独存排序后的状态,直接用派生值计算+空值兜底即可:

  • 给异步请求返回的数据加空值判断,数据未就绪时返回空数组,避免访问不存在的属性
  • 用useMemo基于allFeedData计算排序后的列表数据,源数据更新时会自动重新计算排序结果,不需要手动赋值
  • 去掉挂载时手动调用allFeedRefetch()的逻辑,useQuery默认挂载时就会自动发起请求,不需要重复触发
  • 下拉刷新时等待refetch完成后再结束刷新状态

修复后的完整代码参考:

// 从useQuery中导出loading状态方便做加载态判断(可选)
const { data: allFeedData, refetch: allFeedRefetch } = useQuery(SEE_ALL_FEED_ORDER);
const [refreshing, setRefreshing] = useState(false);

// 直接派生排序后的数据,不需要额外存state
const flatlistdata = useMemo(() => {
  // 空值兜底:数据未返回时直接返回空数组
  if (!allFeedData?.seeAllFeedOrder) return [];
  // 数据存在时再做排序
  return [...allFeedData.seeAllFeedOrder].sort((a, b) => {
    return b.directFeedNumber - a.directFeedNumber;
  });
}, [allFeedData]);

// 下拉刷新逻辑
const refresh = useCallback(async () => {
  setRefreshing(true);
  await allFeedRefetch();
  setRefreshing(false);
}, [allFeedRefetch]);

// FlatList直接使用派生的排序数据即可,数据为空时不会报错
<FlatList
  data={flatlistdata}
  keyExtractor={(item) => item.id}
  renderItem={RankRow}
  refreshing={refreshing}
  onRefresh={refresh}
/>
额外注意点

如果你一定要用useEffect+useState的写法,必须把allFeedData加到useEffect的依赖数组里,同时在effect内部做空值判断,否则永远会出现首次执行拿不到数据的问题,但这种写法会多一次状态更新,性能不如直接用useMemo派生数据的方案。

内容的提问来源于stack exchange,提问作者Hyejung

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 12:06:18