页面启动时useQuery返回data为undefined引发报错如何解决
报错核心原因
你遇到的undefined is not an object和渲染时机无关,是代码逻辑本身的问题:
useQuery是异步请求,组件首次挂载、useEffect执行时,请求还没返回,此时allFeedData的值为undefined,你直接读取allFeedData.seeAllFeedOrder属于访问undefined上的属性,会直接抛错。allFeedRefetch()是异步方法,你调用后没有等待请求返回就立刻读取allFeedData,此时拿到的还是请求未完成的undefined值。- 你的useEffect依赖是空数组,只会在组件挂载时执行一次,就算后续请求返回、
allFeedData更新了,排序和赋值逻辑也不会再重新执行,最终存入state的数据永远是首次执行时的错误值。 - 额外用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
相关产品推荐
相关产品推荐

