question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Table rows are re-rendered when datasource is strictly equal

See original GitHub issue

Version

2.9.1

Environment

osx 10.10.5 with Chrome 57

Reproduction link

https://codepen.io/foxxmd/pen/GmqojV

Steps to reproduce

  • Create a <Table/> inside a Component <X> that receives
    • a prop for the table dataSource (ex, list)
    • props not for table
  • Update any props for <X> that are not list

To see what is re-rendered using the provided codepen open the browser console and click “Run” again.

What is expected?

Since this.props.list === nextProps.list I would expect that <Table> would not re-render any <TableRow> or <TableCell> components

What is actually happening?

All <TableRow> and <TableCell> components are re-rendered.


After reading (google translating) these issues

I was under the impression the re-render was due to custom render functions in the columns properties but the reproduced codepen verifies that the re-render occurs regardless.

This causes a huge performance hit even when not interacting with the table since the table re-renders any time props are updated. These are the performance metrics for a 40 row, 6 column table in my app.

Additionally adding rowSelection to the <Table> causes all checkboxes to have DOM operations performed on them. I’m not sure if this is related to the re-renders specifically but its also a huge performance hit.

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:10 (6 by maintainers)

github_iconTop GitHub Comments

2reactions
FoxxMDcommented, Jun 13, 2018

I did a few things because I found even more props on Table were causing the whole component to re-render when I didn’t need it to:

  • Styled components to emulate DOM wrapping Table and Title component of Table
  • So Title component is updated separately from Table because my scenario has components in Title re-rendering based on row selection but this didn’t require re-rendering every row in Table (since data was the same)
import React from 'react';
import { Table, Spin } from 'antd';
import styled from 'styled-components';
import { onlyUpdateForKeys, pure, compose } from 'recompose';
import { omitProps } from '../utils/HocUtil';

// styled components to emulate Table and title part of Table
const StyledDiv   = styled.div`
// styling
 `;
const StyledTitle = styled.div`
// styling
`;

const enhance = props =>
	<StyledTitle>{props.children}</StyledTitle>;
const Title   = onlyUpdateForKeys( [ 'children' ] )( enhance );

const enhancedWithTitleTable = compose(
	omitProps( [ 'title', 'loading' ] ),
	onlyUpdateForKeys( [ 'dataSource', 'pagination', 'progressingIds', 'loading', 'expandedRows', 'columns', 'rowSelection' ] )
);

const enhancedTable = compose(
	omitProps( [ 'title' ] ),
	onlyUpdateForKeys( [ 'dataSource', 'pagination', 'progressingIds', 'loading', 'expandedRows', 'columns', 'rowSelection' ] )
);

const RealPureTable          = enhancedTable( Table );
const RealPureTableWithTitle = enhancedWithTitleTable( Table );

const PureTable = ( props ) =>{
  if(props.noTitle) {
	return <RealPureTable {...props} />;
  }
  return (<Spin spinning={props.loading}>
	<StyledDiv>
	  <Title>{props.title}</Title>
	  <RealPureTableWithTitle {...props} />
	</StyledDiv>
  </Spin>);
};

export default pure( PureTable );

Additionally, when using PureTable, I use createSelector from reselect to provide data to the columns prop because it was also causing a re-render of the whole table even when the data was equal (but not the exact same object)

import React from 'react';
import { createSelector } from 'reselect';
import { Input, Tooltip } from 'antd';
import editable from '../components/Editable/EditableInputHOC';
import PureTable from '../components/Table/PureTable';

const EditName = editable()( Input );

class Container extends React.Component {
  construct( props ){
	super( props );
	
	this.columnsSelector = createSelector(
		p => p.lexicon,
		p => p.merchants,
		p => p.canEdit,
		( lexicon, merchants, canEdit ) => [ {
		  title: 'Id',
		  dataIndex: 'id',
		},
		  {
			title: 'Merchant',
			dataIndex: 'merchant.id',
			render: ( id ) =>{
			  const merchant = merchants.find( x => x.id === id );
			  return merchant === undefined ? id : merchant.name;
			},
		  },
		  {
			title: 'Name',
			dataIndex: 'name',
			render: ( name, record ) =>{
			  if(canEdit) {
				return (<EditName editable
								  display={name}
								  defaultValue={name}
								  style={{ width: '80%' }}
								  onChange={val => this.handleSkuNameChange( val, record.id )}/>);
			  }
			  return name;
			},
		  },
		  {
			title: 'Item Count',
			dataIndex: 'productCount',
		  }
		] );
  }
  
  render(){
	return (<PureTable columns={this.columnsSelector( this.props )}/>);
  }
}
1reaction
FoxxMDcommented, Jun 13, 2017

No problem thanks for the response. Yeah I ended up using onlyUpdateForKeys from recompose and wrapping the table. Good to know about the checkbox bug,

Read more comments on GitHub >

github_iconTop Results From Across the Web

antd Table is not automatically rerendered when datasource ...
If you want a Table to re-render automatically, filteredData should be state. onSourceChange = (something) => { this.
Read more >
JavaScript Data Grid Configuration options - Handsontable
A complete list of Handsontable's configuration options that let you customize your data grid instance.
Read more >
Element: <oj-table> - Oracle
Make the current row readonly. Column Header, Tab, Navigate to next focusable element on page (outside table). Shift+Tab, Navigate ...
Read more >
Changelog - Datafold
It can be applied to both tables and columns. Data Source and Data App source filters in Catalog are now merged for better...
Read more >
Use trackBy in Angular ngFor Loops and MatTables
A missing trackBy in an ngFor block or a data table can often result ... be equivalent to the previous ones, Angular uses...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found