Material-table: Same-key error when data contains multiple references to the same variable

Created on 29 Jul 2019  Â·  3Comments  Â·  Source: mbrn/material-table

Describe the bug
When data attribute is an array of objects referring to the same variable multiple times caues React to complain about the same key assigned to different elements.

import React from 'react';
import ReactDOM from 'react-dom';
import MaterialTable from 'material-table';

const columns = [
  { title: 'Name', field: 'name' },
  { title: 'Surname', field: 'surname' },
];

const defaultRow = {
  name: 'John',
  surname: 'Doe',
};

function App() {
  return (
    <div style={{ maxWidth: '100%' }}>
      <MaterialTable
        title="Preview"
        columns={columns}
        data={[defaultRow, defaultRow]}
      />
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById('root'));

Error:

Warning: Encountered two children with the same key, `row-1`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.
    in tbody (created by ForwardRef(TableBody))
    in ForwardRef(TableBody) (created by WithStyles(ForwardRef(TableBody)))
    in WithStyles(ForwardRef(TableBody)) (created by MTableBody)
    in MTableBody (created by Droppable)
    in table (created by ForwardRef(Table))
    in ForwardRef(Table) (created by WithStyles(ForwardRef(Table)))
    in WithStyles(ForwardRef(Table)) (created by Droppable)
    in div (created by Droppable)
    in div (created by Droppable)
    in Droppable (created by ConnectFunction)
    in ConnectFunction
    in ConnectFunction (created by MaterialTable)
    in div (created by ScrollBar)
    in ScrollBar (created by MaterialTable)
    in div (created by ForwardRef(Paper))
    in ForwardRef(Paper) (created by WithStyles(ForwardRef(Paper)))
    in WithStyles(ForwardRef(Paper)) (created by Container)
    in Container (created by MaterialTable)
    in Provider (created by App)
    in App (created by ErrorBoundary)
    in ErrorBoundary (created by DragDropContext)
    in DragDropContext (created by MaterialTable)
    in MaterialTable
    in Unknown (created by WithStyles(Component))
    in WithStyles(Component) (created by App)
    in div (created by App)
    in App

To Reproduce
Demo here

Expected behavior
No error.

Desktop (please complete the following information):

  • OS: OpenSuSE Tumbleweed
  • Browser chrome
  • Version 75.0.3770.142
bug

All 3 comments

Actually this is not a bug. You can create rows with {...defaultRow} instead of defaultRow

@mbrn this works but feels a little clumsy.

const defaultRow = {
  name: 'John',
  surname: 'Doe',
};
const defaultRow2 = {
  name: 'Jane',
  surname: 'Doe',
};

function App() {
  return (
    <div style={{ maxWidth: '100%' }}>
      <MaterialTable
        title="Preview"
        columns={columns}
        data={[{...defaultRow}, {...defaultRow}, defaultRow, defaultRow2]}
      />
    </div>
  );
}

The user of the material-table component shouldn't care about where the data comes from and if it contains any duplicates (using the same variable as in this case). Doing a shallow copy of every but one occurence of a row just to evade the warning feels awkward.

BTW, it works and changed my usecase to use the shallow copy. At least, a deep copy is not needed, so shouldn't make much difference in performance.

I suggest writting a wrapper that will remove all the references.

import React from 'react';
import ReactDOM from 'react-dom';
import MaterialTable from 'material-table';

const columns = [
  { title: 'Name', field: 'name' },
  { title: 'Surname', field: 'surname' },
];

const defaultRow = {
  name: 'John',
  surname: 'Doe',
};

const defaultRow2 = {
  name: 'Jane',
  surname: 'Doe',
};

const defaultRow3 = defaultRow2;

function MaterialTableWrapper({ data, ...props }) {
  return <MaterialTable {...props} data={data.map(item => ({ ...item }))} />;
};

function App() {
  return (
    <div style={{ maxWidth: '100%' }}>
      <MaterialTableWrapper
        title="Preview"
        columns={columns}
        data={[defaultRow, defaultRow2, defaultRow3]}
      />
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById('root'));
Was this page helpful?
0 / 5 - 0 ratings

Related issues

revskill10 picture revskill10  Â·  3Comments

behrouz-s picture behrouz-s  Â·  3Comments

kfirshahar picture kfirshahar  Â·  3Comments

VipinJoshi picture VipinJoshi  Â·  3Comments

lazeebee picture lazeebee  Â·  3Comments