The updateCells
prop passed down from Table to Cell is responsible for rerendering all the cells in the table, and it’s triggered when a Cell changes its content.
This is because another Cell might reference ours in a formula, and multiple Cells could need to be updated because of a change in another Cell.
At the moment we’re blindly updating all cells, which is a lot of rerendering. Imagine a big table, and the amount of computation needed to rerender could be bad enough to cause some problems.
We need to do something: implement the shouldComponentUpdate()
in Cell.
The Cell.shouldComponentUpdate()
is key to avoiding performance penalties in re-rendering the whole table:
//...
/**
* Performance lifesaver as the cell not touched by a change can
* decide to avoid a rerender
*/
shouldComponentUpdate(nextProps, nextState) {
// Has a formula value? could be affected by any change. Update
if (this.state.value !== '' &&
this.state.value.slice(0, 1) === '=') {
return true
}
// Its own state values changed? Update
// Its own value prop changed? Update
if (nextState.value !== this.state.value ||
nextState.editing !== this.state.editing ||
nextState.selected !== this.state.selected ||
nextProps.value !== this.props.value) {
return true
}
return false
}
//...
What this method does is: if there is a value, and this value is a formula, yes we need to update as our formula might depend on some other cell value.
Then, we check if we’re editing this cell, in which case - yes, we need to update the component.
In all other cases, no we can leave this component as-is and not rerender it.
In short, we only update formula cells, and the cell being modified.
We could improve this by keeping a graph of formula dependencies that can trigger ad-hoc re-rendering of dependent cells of the one modified, which is an optimization that with large amounts of data can be a lifesaver, but it might even be causing delays itself, so I ended up with this basic implementation.