Reputation: 309
I have a code snippet like this
<Table selectable onRowSelection={this.onRecordSelected} bodyStyle={tableBodyStyle}>
<TableBody deselectOnClickaway={false} showRowHover displayRowCheckbox={false}>
{this.props.taskRecords.map((row, index) => (
<TableRow key={row.get('id')} selected={this.state.selectedRecordRowId === index}>
<TableRowColumn>{row.getIn(['task', 'name'])}</TableRowColumn>
<TableRowColumn>{row.getIn(['task', 'description'])}</TableRowColumn>
<TableRowColumn>{row.get('status')}</TableRowColumn>
<TableRowColumn>{row.get('log')}</TableRowColumn>
</TableRow>
))}
</TableBody>
</Table>
I checked the source code of TableRow
and TableRowColumn
, I found they didn't implement shouldComponentUpdate
method. I understand they would be rerendered when any state is changed.
I tried to use pure
function in recompose
library to purify these to components.
const TableRow = pure(require('material-ui/lib/table/table-row'));
const TableRowColumn = pure(require('material-ui/lib/table/table-row-column'));
In my understanding, components after purified wouldn't be rerendered anymore if given props
are not changed. In this case, all props are either Immutable objects from Immutable.js
or functions.
Is there any way to prevent it from rerendering when I select any row?
Thank you in advance.
Upvotes: 2
Views: 2858
Reputation: 309
Finally I found a solution.
<Table selectable onRowSelection={this.onRecordSelected} bodyStyle={tableBodyStyle}>
<TableBody deselectOnClickaway={false} showRowHover displayRowCheckbox={false}>
{this.props.taskRecords.map((row, index) => (
<PureRecordRow key={row.get('id')} selected={this.state.selectedRecordRowId === index}>
<TableRowColumn>{row.getIn(['task', 'name'])}</TableRowColumn>
<TableRowColumn>{row.getIn(['task', 'description'])}</TableRowColumn>
<TableRowColumn>{row.get('status')}</TableRowColumn>
<TableRowColumn>{row.get('log')}</TableRowColumn>
</PureRecordRow>
))}
</TableBody>
</Table>
I created a new component PureRecordRow
which extends the TableRow
with custom shouldComponentUpdate
method:
class PureRecordRow extends TableRow{
constructor(props, context){
super(props, context)
}
shouldComponentUpdate(nextProps, nextState) {
return this.state.hovered !== nextState.hovered || this.props.selected !== nextProps.selected;
}
}
Upvotes: 2
Reputation: 1844
In general, yes - render
function will be called each time in TableRow
and TableRowColumn
if their parent component will be rerendered, but it is not so bad, because render
function do not change your RealDOM each time, so it is not so bad for your application performance.
But, if you really want to prevent that because of reasons, you can for example create new component MyRow
and render it instead of TableRow + TableRowColumn
.
So, your code will be like:
<Table selectable onRowSelection={this.onRecordSelected} bodyStyle={tableBodyStyle}>
<TableBody deselectOnClickaway={false} showRowHover displayRowCheckbox={false}>
{this.props.taskRecords.map((row, index) => (
<MyRow key={index} row={row} isSelected={this.state.selectedRecordRowId === index} />
))}
</TableBody>
</Table>
And in MyRow
component you can implement shouldComponentUpdate
(or PureRenderMixin
) and render real material-ui components:
render() {
var isSelected = this.props.isSelected;
var row = this.props.row;
return <TableRow key={row.get('id')} selected={isSelected}>
<TableRowColumn>{row.getIn(['task', 'name'])}</TableRowColumn>
<TableRowColumn>{row.getIn(['task', 'description'])}</TableRowColumn>
<TableRowColumn>{row.get('status')}</TableRowColumn>
<TableRowColumn>{row.get('log')}</TableRowColumn>
</TableRow>
}
Upvotes: 1