Devextreme-reactive: Rerenders with every keystroke

Created on 27 Apr 2018  路  6Comments  路  Source: DevExpress/devextreme-reactive

I have a table of about 200 rows (and 8 or so columns), but it is really slow at Filtering for example. When using React Tools and switch on Highlight Updates, every single cell, every single row - everything is updated with every keystroke in the filter box. It takes a few seconds just to be able to even type out a 5 letter word in the filter box.

Filtering is not the only slow thing. Triggering an edit or delete takes over a second or two too.

I've seen your code handle 200000 rows fine - so I have no doubt that internally the grid is set up well, but I am wondering whether I am perhaps not using it or setting up correctly on my end.

I am not sure where to look - but I have a feeling it is really obvious. I have attached my code for displaying the table - is somebody able to quickly point me in the right direction?

https://gist.github.com/joergd/2c909a7b7bca74af84a2e51b810e8aab

Grid question

Most helpful comment

Hi @joergd,

You define some components like Cell, HeaderCell etc. right in the render() method of your TradeTable component. And this will force React to create new instances for them on each render. As a solution, please try to extract these components beyond the TradeTable definition.

All 6 comments

Hi @joergd,

You define some components like Cell, HeaderCell etc. right in the render() method of your TradeTable component. And this will force React to create new instances for them on each render. As a solution, please try to extract these components beyond the TradeTable definition.

I have extracted them beyond the TradeTable definition, and it has improved things - all cells still seem to rerender when I click on the Edit link for a row for example - though the rows no longer rerender at least - so it's already faster. I'll look more into it, to see why cells still rerender. I took a look at your demo page, and there the cells of the other rows don't rerender when I click on a row edit link.

Besides that - but then what to do with something like

const HeaderCell = ({ children }) => {
  return (
    <TableEditColumn.HeaderCell>
      {children}
      {selection.length > 0 &&
        <Button
          color="primary"
          onClick={() => {
            this.props.commitChanges({ deleted: selection })
          }}
          title="Delete multiple trades"
          size="small"
          className={classes.deleteButton}
        >
          <Delete />
        </Button>
      }
    </TableEditColumn.HeaderCell>
  )
}

Here I am relying on the state to get which rows have been selected, so that I can have a multi-delete button in the header. Is there a way to work around this when I need to define the HeaderCell outside of the Table definition?

As I said - this improved my situation a lot - however it was still rerendering a number of the cells when it didn't need to. So when I click on an Edit link for a row - it will rerender all the cell of all rows.

But I have now narrowed down what _all_ cells are. It's all the cells that are set up with a DataTypeProvider - as some of the cells need special formatting like currencies and dates. All these cells rerender all the time - when I click on row Edit links, or edit a value in a row (with every keypress). Is this a bug? Or did I also not configure something correctly?

@joergd I encountered the exact same problem, and I was scratching my head trying to figure out why. Just bear these two things in mind:

  1. Always extract beyond definition the callbacks that involve creating new components.
  2. Always try to create sub components that can be directly used by the component containing the Grid component, and maintain your local state within those sub components. This way, React would not re-render the whole grid, only your sub components. This approach solved my problem.

I still have the same issue - I had an improvement not defining Cell etc inside the render. I till define the HeaderCell inside the render() method now as I need access to the props for my component (I don't think there is currenty a way to pass them into the HeaderCell component.) Either way if I comment out the HeaderCell definition and remove the reference to it - it doen't make any real difference anyway).

If I click on the Edit link for example for a row - everything is rerendered. Or if I exit the popup edit dialog - again all the cells are rerendered. See my Table component below.

class TradeTable extends React.PureComponent {
  constructor(props) {
    super(props)

    this.state = {
      columns: [
        { name: "trade_type", title: "Type" },
        { name: "buy", title: "Buy quantity" },
        { name: "buy_symbol", title: "Buy asset" },
        { name: "sell", title: "Sell quantity" },
        { name: "sell_symbol", title: "Sell asset" },
        { name: "fee", title: "Fee" },
        { name: "fee_symbol", title: "Fee asset" },
        { name: "exchange", title: "Exchange" },
        { name: "timestamp", title: "Trade date" },
        { name: "label", title: "Label" },
        { name: "comment", title: "Comment" },
      ],
      tableColumnExtensions: [
        { columnName: "trade_type", width: 70 },
        { columnName: "buy_symbol", width: 78 },
        { columnName: "sell_symbol", width: 78 },
        { columnName: "fee_symbol", width: 78 },
        { columnName: "exchange", width: 90 },
      ],
      integratedFilteringColumnExtensions: [{ columnName: "timestamp", predicate: timestampPredicate }],
      sorting: [{ columnName: "timestamp", direction: "desc" }],
      searchValue: "",
    }
  }

  changeSearchValue = value => this.setState({ searchValue: value })
  changeSorting = sorting => this.setState({ sorting })

  render() {
    const { trades, addedRows, editingRowIds, rowChanges, deletingRows, selection } = this.props
    const { changeAddedRows, changeEditingRowIds, changeRowChanges, commitChanges, cancelDelete, deleteRows, changeSelection } = this.props
    const { columns, tableColumnExtensions, editingColumnExtensions, integratedFilteringColumnExtensions, sorting, searchValue } = this.state

    const HeaderCell = ({ children }) => {
      const { selection, classes, commitChanges } = this.props
      return (
        <TableEditColumn.HeaderCell>
          {children}
          {selection.length > 0 &&
            <Button
              color="primary"
              onClick={() => {
                commitChanges({ deleted: selection })
              }}
              title="Delete multiple trades"
              size="small"
              className={classes.deleteButton}
            >
              <Delete />
            </Button>
          }
        </TableEditColumn.HeaderCell>
      )
    }


    return (
      <Paper elevation={0} style={{ maxWidth: "1140px" }} >
        <Grid rows={trades} columns={columns} getRowId={getRowId}>
          <DateTimeTypeProvider for={["timestamp"]} />
          <QuantityTypeProvider for={["buy", "sell", "fee"]} />
          <SearchState value={searchValue} onValueChange={this.changeSearchValue} />
          <SortingState sorting={sorting} onSortingChange={this.changeSorting} />
          <SelectionState selection={selection} onSelectionChange={changeSelection} />
          <IntegratedFiltering columnExtensions={integratedFilteringColumnExtensions} />
          <IntegratedSorting />
          <IntegratedSelection />
          <EditingState
            columnExtensions={editingColumnExtensions}
            addedRows={addedRows}
            onAddedRowsChange={changeAddedRows}
            editingRowIds={editingRowIds}
            onEditingRowIdsChange={changeEditingRowIds}
            rowChanges={rowChanges}
            onRowChangesChange={changeRowChanges}
            onCommitChanges={commitChanges}
          />
          <VirtualTable tableComponent={TableComponent} cellComponent={Cell} columnExtensions={tableColumnExtensions} height={700} />
          <TableHeaderRow showSortingControls />
          <TableSelection cellComponent={TableSelectionComponent} headerCellComponent={TableSelectionHeaderComponent} showSelectAll />
          <TableEditColumn showAddCommand={!addedRows.length} showEditCommand showDeleteCommand headerCellComponent={HeaderCell} commandComponent={Command} />
          <EditDialogPlugin popupComponent={EditDialog} />
          <Toolbar />
          <SearchPanel />
        </Grid>
        <ConfirmDelete deletingRows={deletingRows} cancelDelete={cancelDelete} deleteRows={deleteRows} />
      </Paper>
    )
  }
}

This thread has been automatically locked since it is closed and there has not been any recent activity. Please open a new issue for related bugs or feature requests.

Was this page helpful?
0 / 5 - 0 ratings