材料表类型错误:无法添加属性表数据,对象不可扩展

J. *_*018 12 javascript reactjs material-ui axios material-table

我正在meterial-tableReact. 我正在尝试从来自这样的 api 的数组中分配数据

<MaterialTable
  columns={columns}
  data={rows}
  ...
/>
Run Code Online (Sandbox Code Playgroud)

在哪里columnsrows在API数据。但我收到此错误:

TypeError: Cannot add property tableData, object is not extensible
Run Code Online (Sandbox Code Playgroud)

值得注意的是,当我使用模拟硬编码数据时,一切正常。经过一番搜索,我找不到任何解决方案,有什么帮助吗?

Tob*_*ist 19

您很可能正在使用immer或 一个immer在幕后使用的库(如@reduxjs/toolkit)。immer用于Object.freeze使其生成的对象不可变。

material-table修改自己的道具(这是一个非常丑陋的反模式)。当图书馆违反规则时,它们将不会与试图强制执行规则的图书馆合作。

无法解冻已冻结的对象,但您有以下几种选择:

  1. 找到一种在 immer 实例中禁用冻结的方法(查看 API 文档,了解您认为可能冻结您的状态的任何内容)。

  2. 覆盖Object.freeze使它什么都不做(非常hacky,应该避免 - 但它可能是你最好的镜头):

window.Object.freeze = function(obj) { return obj }
Run Code Online (Sandbox Code Playgroud)
  1. 在将状态传递给MaterialTable. 这也远非理想,尤其是当您有大量数据时。

  • 非常感谢您的建议/解释。我使用“immer”时遇到了完全相同的问题。值得庆幸的是,`immer`确实提供了禁用冻结的功能:`import { setAutoFreeze } from 'immer'; 设置自动冻结(假);` (3认同)

Sir*_*keh 16

这与material-table或无关React。这很可能与您Object.preventExtensions()出于某种原因对其应用的 api 响应有关,也许这是一种Axios行为。所以当material-table试图向id每个对象添加一个字段时,它面临这个错误。虽然不是最优的,但尝试将您的 api 数据复制到一个新的对象数组,以便material-table可以修改它们,例如:

const editable = rows.map(o => ({ ...o }));
Run Code Online (Sandbox Code Playgroud)
<MaterialTable
  columns={columns}
  data={editable}
  ...
/>
Run Code Online (Sandbox Code Playgroud)

请注意,我没有使用,rows.map(o => o)因为这将复制具有相同对象引用的数组

编辑:值得一提的是,使用扩展运算符Object.assign只会提供浅拷贝,即不会复制嵌套对象。一种解决方法是使用JSON.parse(JSON.stringify(object)). 请注意,这会导致一些数据丢失,此答案中有其他替代方案: 在 JavaScript 中深度克隆对象的最有效方法是什么?