Skip to content

Instantly share code, notes, and snippets.

@mistakster
Last active September 13, 2022 01:04
Show Gist options
  • Save mistakster/2d97a72814680d5069df214225c96a5d to your computer and use it in GitHub Desktop.
Save mistakster/2d97a72814680d5069df214225c96a5d to your computer and use it in GitHub Desktop.
Optimizing performance of the React list component

Optimizing performance of the React list component

Basically, everything need to be done in shouldComponentUpdate() method.

import React, {Component} from 'react';

class Item extends Component {
  shouldComponentUpdate(nextProps, nextState) {
    // always re-render component
    return true;
  }
  render() {
    return (
      <div/>
    );
  }
}

If we don’t mind compare all properties, we can use pre-defined implementation.

import React, {PureComponent} from 'react';

class Item extends PureComponent {
  render() {
    return (
      <div/>
    );
  }
}

Also we can create relevant enhancer much easier with recompose:

Demo

https://bl.ocks.org/mistakster/2d97a72814680d5069df214225c96a5d

It works only in Chrome and Firefox. See console for re-render updates.

(function () {
/**
* Helper function which creates initial list with mock data
*/
function getInitialList() {
return _.range(10)
.map(n => ({
id: n,
title: `Item #${n}`,
color: '#fff'
}));
}
/**
* Helper function which generates random value for the color component (red, green, blue)
*/
function getRandomColorHexValue() {
return Math.round(7 + 8 * Math.random()).toString(16);
}
/**
* Dumb item component
* It will print a message in console every time React invoke it
*/
function ItemComponent({changeColor, item: {id, title, color}}) {
console.log(`Render item: #${id}`);
return React.createElement(
'div',
{
style: {
backgroundColor: color,
padding: '10px',
borderTop: '1px solid #ddd',
borderBottom: '1px solid #ddd',
}
},
React.createElement(
'span',
null,
title
),
React.createElement(
'button',
{
onClick: changeColor,
style: {
marginLeft: '10px'
}
},
'Change color'
)
)
}
/**
* Item enhancer to apply optimizations and action hanlers
*/
const Item = Recompose.compose(
// This HOC is basically controlled version of `Recompose.pure` or React.PureComponent
Recompose.shouldUpdate((props, nextProps) => {
if (!props.optimization || props.optimization !== nextProps.optimization) {
return true;
}
return !Recompose.shallowEqual(props, nextProps);
}),
Recompose.withHandlers({
changeColor: props => () => {
const {updateItem, item} = props;
const r = getRandomColorHexValue();
const g = getRandomColorHexValue();
const b = getRandomColorHexValue();
return updateItem({
...item,
color: `#${r}${g}${b}`
});
}
}),
Recompose.mapProps(props => _.omit(props, ['updateItem']))
)(ItemComponent);
/**
* Dumb list component
*/
function ListComponent({list, optimization, updateItem, updateOptimization}) {
return React.createElement(
'div',
null,
React.createElement(
'button',
{
onClick: () => {
updateOptimization(!optimization);
}
},
optimization ? 'Disable optimization' : 'Enable optimization'
),
React.createElement(
'div',
{
style: {
marginTop: '10px'
}
},
list.map(item => (
React.createElement(Item, {key: item.id, updateItem, item, optimization})
))
)
);
}
/**
* List enhancer which owns the state
*/
const List = Recompose.compose(
Recompose.withStateHandlers({
list: getInitialList(),
optimization: false
}, {
updateList: () => list => ({list}),
updateOptimization: () => optimization => ({optimization})
}),
Recompose.withHandlers({
updateItem: props => nextItem => {
const {list, updateList} = props;
updateList(list.map(item => {
return item.id === nextItem.id ? nextItem : item
}));
}
}),
Recompose.mapProps(props => _.omit(props, ['updateList']))
)(ListComponent);
/**
* Render the app
*/
ReactDOM.render(
React.createElement(List),
document.getElementById('app')
);
}());
<!DOCTYPE html>
<html>
<head>
<title>Repaint</title>
</head>
<body>
<div id="app"></div>
<script crossorigin src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>
<script crossorigin src="https://unpkg.com/[email protected]/build/Recompose.js"></script>
<script crossorigin src="https://unpkg.com/[email protected]/lodash.js"></script>
<script src="app.js"></script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment