gregnb / gregnb/mui-datatables

Generating dynamic column definitions fails with too many columns (maximum call stack size exceeded)

Open
#752 11 comments 0 reactions 0 assignees View on GitHub
needs verification
Dominant language
JavaScript
Stars
2.7k
Forks
906
PR merge metrics
No merged PRs in 30d

Description

## Expected Behavior

The ability to change the column definitions in runtime is important, because I often need to pass props to the `options.customBodyRender` function in columns.
I expect this to work by using the columns I pass in the props, and when updating them it should reflect the changes without error.

## Current Behavior

Currently if there are too many columns and the array is rebuilt, mui-datatables internally creates a deep clone of the array (using lodash) which fails with max call stack size exceeded error. It's an infinite loop.

Here is the stack trace:

```
Uncaught RangeError: Maximum call stack size exceeded
at baseClone (index.js:875)
at eval (index.js:946)
at arrayEach (index.js:130)
at baseClone (index.js:939)
at eval (index.js:946)
at arrayEach (index.js:130)
at baseClone (index.js:939)
at eval (index.js:946)
at arrayEach (index.js:130)
at baseClone (index.js:939)
at eval (index.js:946)
at arrayEach (index.js:130)
at baseClone (index.js:939)
at cloneMap (index.js:1093)
at initCloneByTag (index.js:1372)
at baseClone (index.js:921)
at eval (index.js:946)
at arrayEach (index.js:130)
at baseClone (index.js:939)
at eval (index.js:946)
at arrayEach (index.js:130)
at baseClone (index.js:939)
at eval (index.js:946)
at arrayEach (index.js:130)
at baseClone (index.js:939)
at eval (index.js:946)
at arrayEach (index.js:130)
at baseClone (index.js:939)
at eval (index.js:946)
at arrayEach (index.js:130)
at baseClone (index.js:939)
at cloneMap (index.js:1093)
at initCloneByTag (index.js:1372)
at baseClone (index.js:921)
at eval (index.js:946)
at arrayEach (index.js:130)
at baseClone (index.js:939)
at eval (index.js:946)
at arrayEach (index.js:130)
at baseClone (index.js:939)
at cloneMap (index.js:1093)
at initCloneByTag (index.js:1372)
at baseClone (index.js:921)
at eval (index.js:946)
at arrayEach (index.js:130)
at baseClone (index.js:939)
at eval (index.js:946)
at arrayEach (index.js:130)
at baseClone (index.js:939)
at eval (index.js:946)
```

## Steps to Reproduce (for bugs)

1. Have multiple columns defined inside your render function, or generated by using a function that takes props and returns column definitions. For me, anything above 11 or 12 columns will trigger the bug, but less than that it works - albeit with a small rendering delay when updating.
2. Attempt to sort using any of the columns
3. Receive exception (above)

## Your Environment

| Tech | Version |
|--------------|---------|
| Material-UI | 4.1.3 |
| MUI-datatables | 2.6.1 |
| React | 16.8.2 |
| browser | brave (Chromium) |

## Example code

```javascript
const Trips = ({ classes, ...props }) => {
/** @type {MUIDataTableColumnDef[]>} */
const tripsColumns = [
{ name: '', label: 'Actions', options: { customBodyRender: (_, meta) => , print: false } },
{ name: 'company', label: 'Company', options: { customBodyRender: v => (e.preventDefault(), e.stopPropagation(), props.handleCompanyChange({ label: v.name, value: v.id, raw: v }))}>{v.name} } },
{ name: 'id', label: 'ID', options: { customBodyRender: v => {v} } },
{ name: 'status', label: 'Status', options: { customBodyRender: v => capitalize(v.replace('_', ' ')) } },
{ name: 'created_by', label: 'Planner', options: { customBodyRender: v => `User #${v}` } },
{ name: 'start_dt', label: 'Start Date', options: { customBodyRender: v => {moment(v).format('MMM DD, YY')} } },
{ name: 'end_dt', label: 'End Date', options: { customBodyRender: v => {moment(v).format('MMM DD, YY')} } },
{ name: 'travelers', label: 'Travelers', options: { customBodyRender: v => smartJoin(v.map(t => firstNameAndLastInitial(t)), 2, '', v.length <= 2 ? ', ' : ' +'), sort: false } },
{ name: 'sent_for_approval', label: 'Sent for Approval', options: { customBodyRender: v => v ? moment(v).format('MMM DD, YY') : '-' } },
{ name: 'approved', label: 'Approved', options: { customBodyRender: v => v ? moment(v).format('MMM DD, YY') : '-' } },
{ name: 'approvers', label: 'Approvers', options: { customBodyRender: v => smartJoin(v.map(t => firstNameAndLastInitial(t)), 2, '', v.length <= 2 ? ', ' : ' +'), sort: false } },
{ name: 'flights_cost', label: Flights $, options: { customBodyRender: v => currency(v) } },
{ name: 'hotels_cost', label: Hotels $, options: { customBodyRender: v => currency(v) } },
{ name: 'surcharges_cost', label: Extras $, options: { customBodyRender: v => currency(v) } },
{ name: 'total_spend', label: Total $, options: { customBodyRender: v => currency(v) } },
];

return (



props.handleCompanyChange(v)} />
props.handleStatusChange(v)} />

props.handleTripSelect(props.trips[meta.rowIndex].id),
onChangePage: page => props.handlePaginationChange({ page: page + 1 }),
onChangeRowsPerPage: page_size => props.handlePaginationChange({ page_size }),
onColumnSortChange: (column, direction) => props.handleSortChange(column, direction),
}} />

);
};
```

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.