Reputation: 4517
My team uses React MaterialUI library. To provide consistent UI Pattern and make it easy for us to customise MaterialUI's component, we wrap each MaterialUI's component in our own component. For example:
const style = {} // our project custom style for ListItemText
const OurListItemText = ({primary, secondary, classes}: Props) => (
<MuiListItemText
primary={primary}
secondary={secondary}
className={classes.text}
/>
) // we only expose primary and secondary props of the original MuiListItemText.
// Team members are blocked from customising other MUIListItemText's props
export default withStyles(styles)(OurListItemText)
MuiListItemText
is the original MaterialUI's component, while OurListItemText
is our wrapper component. In our project, only OurListItemText
is allowed to be used.
As the snippet above, OurListItemText
does nothing but forward the props to MuiListItemText
. However, this affects the performance quite a lot:
ListItemText
bar on the top is from OurListItemText
while the one below is from MuiListItemText
. If we use MuiListItemText
directly, it could be ~50% faster (we have tried), which is noticeable when we have 100 ListItemText
. Removing withStyles
HOC improves a bit, but not significantly.
ListItemText
is only one example, we have similar performance issue on other wrapped components. (2 Typography
in the graph above is another pair of our-wrapper-component and MUI's-original-component)
How to improve the performance of those simple props-forwarding-components?
Upvotes: 16
Views: 1698
Reputation: 3329
If you want raw performance - do not wrap ListItem, but write your replacement instead
List item source doesn't have any extra dependencies, so Ctrl-C, Ctrl-V will work
Then adjust for your needs, remove code you don't need, etc...
That will guarantee max possible performance
The negative side - support cost will grow.
Upvotes: 0
Reputation: 11260
wrapping a React component adds one extra level of full React lifecycle (i.e. the wrapper needs to be mounted). Is it possible to avoid this?
You can avoid the lifecycles by avoiding JSX and calling the functions directly instead.
Eg.
{Component({ data: 1, children: 'Hello' })}
instead of
<Component data={1}>Hello</Component>
This blog post claimed to achieve 45% speed improvement with their test case.
This syntax might not be as readable/understandable though.
Some quote from Dan Abramov regarding this issue:
We're looking at optimizations like this in the context of Prepack but there's nothing that's going to be immediately useable in the next couple of months. Within a year or two we might have something.
Note that unless you're creating thousands of elements, the performance difference won't be noticeable. Also unless your components are very flat and simple, the "pure win" from this optimization will likely be much less relevant in practice.
I wouldn't wait for Prepack to do the optimisation though since the timeline is uncertain and the resulting optimisation might not be identical to this.
As for the significance of the performance improvement, it'd depend on your project and the only way to be certain is to try out and see the improvement for yourself.
Upvotes: 6