React Native useQuery数据渲染前排序报错排查修复
问题根因
报错和条件渲染失效是三个逻辑错误共同导致的:
useEffect依赖项传了空数组,仅会在组件首次挂载完成后执行1次。首次执行时接口还在请求中,allFeedDataLoading值为true,不会进入排序逻辑块;等请求结束allFeedDataLoading变为false、allFeedData拿到返回值时,因为依赖项为空,effect不会重新触发,排序逻辑永远不会执行。如果碰到接口报错、allFeedData为undefined的场景,只要effect意外触发到取值逻辑,直接访问allFeedData.seeAllFeedOrder就会抛出属性不存在的错误。flatlistdata === []这个判断恒为false。JavaScript中数组是引用类型,两个独立创建的空数组内存地址完全不同,这个判断永远不会成立,等于第一个条件渲染逻辑完全没生效。- 仅判断
allFeedDataLoading不足以覆盖边缘场景:Apollo Client的useQuery在请求出错、返回字段缺失的场景下,loading状态可能变为false但data仍然是undefined,没有空值兜底就会触发报错。
修复方案
第一步:修正排序逻辑
不要用空依赖的useEffect存排序结果,优先用useMemo计算派生数据,从根源避免依赖项漏加的问题,同时加空值兜底:
import { useMemo } from 'react'; // 替换原来的useState+useEffect逻辑 const flatlistdata = useMemo(() => { // 数据不存在时直接返回空数组,避免取值报错 if (!allFeedData?.seeAllFeedOrder?.length) return []; // 数据合法时再做排序 return [...allFeedData.seeAllFeedOrder].sort( (a, b) => b.directFeedNumber - a.directFeedNumber ); }, [allFeedData]);
如果坚持要用useState+useEffect实现,必须补全依赖项和空值判断:
const [flatlistdata, setFlatlistdata] = useState([]); useEffect(() => { // 同时判断加载状态、数据合法性 if (!allFeedDataLoading && allFeedData?.seeAllFeedOrder instanceof Array) { setFlatlistdata( [...allFeedData.seeAllFeedOrder].sort( (a, b) => b.directFeedNumber - a.directFeedNumber ) ); } // 把依赖项全部加上,状态变化时自动重跑effect }, [allFeedDataLoading, allFeedData]);
第二步:修正条件渲染逻辑
不要用数组引用相等做判断,直接判断数组长度即可:
// 加载中、或者排序后的数据为空时,展示加载态 if (allFeedDataLoading || flatlistdata.length === 0) { return ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> <ActivityIndicator size={30} /> </View> ) } // 数据准备完成再渲染列表 return ( <FlatList data={flatlistdata} keyExtractor={(item) => item.id} renderItem={RankRow} refreshing={refreshing} onRefresh={() => { refresh(); // 下拉刷新时手动触发接口重拉,数据更新后排序逻辑会自动重跑 allFeedRefetch(); }} /> )
内容的提问来源于stack exchange,提问作者Hyejung
相关产品推荐
相关产品推荐

