useQuery返回数据调用sort报只读属性赋值错误解决方法
报错原因
Apollo Client 的useQuery返回的data是经过Object.freeze处理的只读冻结对象,设计上就不允许开发者直接修改缓存里存储的原始数据。
而Array.sort()属于原地修改方法,执行时会直接改动原数组的元素顺序,对只读属性执行修改操作就会触发Attempted to assign to readonly property报错。
另外你写的排序逻辑本身也有问题:直接对两个对象做a - b运算没有实际排序效果,没有指定按目标字段directFeedNumber做对比。
正确实现方案
- 首先做空值兜底:请求加载阶段
allFeedData值为undefined,直接访问嵌套的seeAllFeedOrder会触发空指针报错 - 禁止直接操作原数组:先通过浅拷贝生成原数组的副本,再对副本执行排序,不会改动原始只读数据
- 排序比较函数中明确指定对比两个元素的
directFeedNumber字段值,数值类型直接做差即可实现升序/降序排列
基础实现代码:
const { data: allFeedData, loading: allFeedLoading } = useQuery(SEE_ALL_FEED_ORDER); const feedSort = allFeedLoading || !allFeedData?.seeAllFeedOrder ? [] // 用展开运算符做浅拷贝生成新数组,再执行排序 : [...allFeedData.seeAllFeedOrder].sort((a, b) => { // 升序用a - b,要降序就调换顺序写 b.directFeedNumber - a.directFeedNumber return a.directFeedNumber - b.directFeedNumber; });
性能优化提示:如果组件重渲染比较频繁,可以用
useMemo缓存排序结果,只有当接口返回数据变化时才重新执行排序:const feedSort = useMemo(() => { if (allFeedLoading || !allFeedData?.seeAllFeedOrder) return []; return [...allFeedData.seeAllFeedOrder].sort((a, b) => a.directFeedNumber - b.directFeedNumber); }, [allFeedData, allFeedLoading]);
注:浅拷贝除了用展开运算符,也可以用Array.slice()实现,效果一致,不需要做深拷贝,避免不必要的性能损耗。所有对useQuery返回数据的修改类操作(比如splice、push、赋值修改属性等)都要基于数据副本执行,不要直接改动原始缓存数据。
内容的提问来源于stack exchange,提问作者Hyejung
相关产品推荐
相关产品推荐

