material-table: TypeError: Cannot add property tableData, object is not extensible

Hello.

Using this table with redux and react-redux. and getting error:

TypeError: Cannot add property tableData, object is not extensible
(anonymous function)
node_modules/material-table/dist/utils/data-manager.js:278
  275 | 
  276 | this.selectedCount = 0;
  277 | this.data = data.map(function (row, index) {
> 278 |   row.tableData = (0, _objectSpread2["default"])({}, row.tableData, {
      | ^  279 |     id: index
  280 |   });
  281 | 

My code looks like:

  const orders = useSelector(state =>
    state.orders
  );
...
        <MaterialTable
          title="Orders"
          isLoading={isLoadingOrders}
          data={orders}
        />

Am I missing something. Thanks!

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 4
  • Comments: 24 (8 by maintainers)

Most upvoted comments

Object.isFrozen(tableData[0]) returns true, so redux toolkit in fact freezes your obejcts. That is causing the errors. I am closing the issue, since this is not a material table error. But the mutation of the passed objects will be removed in the future.

For those coming here due to issue I mentioned earlier (incompatibility with @apollo/client). I have found a temporary workaround. Just to give some background first, Apollo has consolidated all their Apollo related packages into @apollo/client. As part of consolidation InMemoryCache was updated based on this blog post via PR #5073, where they introduced immutability for the cache for performance.

In order to avoid the issue of incompatibility between immutable new Apollo cache and requirement of material-table for data to be mutable, I changed InMemoryCache import to be from apollo-cache-inmemory, which most likely will be deprecated soon. Luckily it still works and can be plugged into new Apollo client.

So I think material-table should still implement a way to work with immutable data, since the workaround I mentioned above is only temporary till old Apollo package will be deprecated.

Hi thanks for the workaround for Apollo. I do not know the exact timeline but I will talk to the other maintainers to get started as soon as possible.

But the mutation of the passed objects will be removed in the future.

How soon? I now migrated from React Apollo 2.6 to 3.1 and in new version Apollo locking objects in Apollo cache. So when using these objects with material-table, getting same error. Its preventing to upgrade to Apollo 3.0 and higher. It is specially annoying, because I’m using editable tree data with material-table. So if I use workaround as mentioned above, after I submit the change and mutate it with Apollo, getting new array from Apollo and original tableData missing, the workaround is recreating it, but all the collapse/expand information missing so the whole table collapses.

I’m also using new @apollo/client and having same issue after upgrade.

I’m not sure why this issue was closed, this is definitely still a problem. The apollo-cache-inmemory repo has not been updated for a year now and is not ideal to use. The latest version of Apollo Client still presents this error when using it’s InMemoryCache package. Is there any scope on when/if this may be fixed? I will likely have to use another library soon as this workaround will be unfit for purpose soon as Apollo Client keeps updating

Same problem with migrating to @apollo/client but I found a more robust solution. If you simply map through the rows and use the function Object.assign({}, buf) you can convert them to writable objects. This works for me. Example:

const [state, setState] = useState<TableState>({
        columns: [
            { title: 'Topic Name', field: 'topic', type: 'string', editable: 'onAdd' },
            { title: 'Current Size', field: 'currSize', type: 'numeric', editable: 'never' },
            { title: 'Packets Expire (T/F)', field: 'expires', type: 'boolean', editable: 'always' },
            { title: 'Experation Time (ms)', field: 'experationTime', type: 'numeric', editable: 'always' },
            { title: 'Is Memory Limited (T/F)', field: 'sizeLimited', type: 'boolean', editable: 'always' },
            { title: 'Memory Limit (bytes)', field: 'maxSize', type: 'numeric', editable: 'always' },
        ],
        data: [],
})
useQuery<BufferQuery>(BufferQuery, {
        onCompleted: (queryData: BufferQuery) => {
            const buffers = queryData.runningBuffers ? queryData.runningBuffers.map(buf => Object.assign({}, buf)) : [];
            setState({ columns: state.columns, data: buffers });
        }
 });
return(<MaterialTable columns={state.columns} data={state.data}
    //...  I deleted all of my on edit stuff here to make this readable                      
 />)

Yes you are creating a new object with that map, what happens if you do not add the empty tabledata object to it? It is possible you freeze your objects so they cannot be changed: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze#:~:text=A frozen object can no,existing properties from being changed.