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

使用RTK Query获取数据时无法修改对象数组属性的问题

RTK Query获取的数据无法修改属性:TypeError: Cannot assign to read only property

问题原因

RTK Query 的 fetchBaseQuery 默认会用 Object.freeze() 冻结返回的响应数据,目的是强制保证状态的不可变性,防止开发者意外修改缓存中的原始数据,避免状态不一致的问题。这就是你修改对象属性时触发只读错误的核心原因——即使复制了数组,若拷贝方式没有完全脱离原冻结对象的引用,依然会遇到权限问题。

解决方案

方案1:使用可靠的深拷贝生成可修改副本

推荐用现代浏览器支持的 structuredClone() 做深拷贝(比 JSON.parse(JSON.stringify) 更可靠,支持更多数据类型):

const Test = () => {
  const {
    data: categories,
    isLoading,
    isSuccess,
    isError,
    error,
  } = useGetCategoriesQuery();

  if (isSuccess) {
    // 生成完全独立的可修改副本
    const categoriesCopy = structuredClone(categories);
    categoriesCopy[0].title = 'new title';
    // 后续可正常操作categoriesCopy
  }

  return <h1>Something rendered</h1>;
};

如果要兼容旧浏览器,JSON.parse(JSON.stringify) 依然可用,但需注意它无法处理函数、循环引用等特殊数据结构。

方案2:在API切片中提前处理响应(可选)

如果希望所有使用该查询的组件都直接拿到可修改的数据,可以在 transformResponse 中提前做深拷贝:

export const apiSlice = createApi({
  reducerPath: 'api',
  baseQuery: fetchBaseQuery({ baseUrl: process.env.devUrl }),
  tagTypes: ['categories'],
  endpoints: (builder) => ({
    getCategories: builder.query({
      query: () => 'categories/includingJobs',
      // 提前深拷贝响应数据,返回可修改对象
      transformResponse: (response) => JSON.parse(JSON.stringify(response.data.data)),
      providesTags: ['categories'],
    }),
  }),
});

方案3:关闭冻结机制(不推荐)

可以在 fetchBaseQuery 配置中关闭数据冻结,但这会破坏RTK的不可变性保证,容易引发意外的缓存修改,仅在特殊场景下使用:

baseQuery: fetchBaseQuery({ 
  baseUrl: process.env.devUrl,
  freeze: false // 关闭数据冻结
}),

注意事项

  • 永远不要直接修改RTK Query返回的原始 data,必须生成副本后再操作
  • 优先使用 structuredClone() 作为深拷贝方式,兼容性和可靠性更好

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 00:55:29