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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 09:39:57