Summary 💡
A common style of getting class names for className prop is the following pattern:
const useStyles = makeStyles(theme => {
root: {
padding: theme.spacing(1),
},
})
The Material UI app is wrapped in ThemeProvider context. A component uses useStyles as follows:
function Component() {
const classes = useStyles();
return <Box className={classes.root}> ... </Box>
}
Changing theme object (via setTheme) causes that all makeStyles callbacks run with new theme, and it generates new set of classes used by application. The components are rerendered so that they read new class names in classes and React will then propagate the changes to browser DOM.
It looks that useStyles hook causes component to render even if there is no real change in class content. Let's take the example makeStyles above. If I can change e.g. a primary color in a theme, new run of makeStyles will return the same as before: root: { padding: 8 }. A component using useStyles could stay the same, there is no need to create new class name and rerender the component.
Proposal: At least some trivial memoizing should be added to makeStyles, so that if theme is changed, but a class returned by makeStyles has the same value, the class should stay the same; if all classes from makeStyles result are the same as before, a component using useStyles should not rerender.
Examples 🌈
const useStyles = makeStyles(theme => {
root: {
padding: theme.spacing(1),
},
child: {
display: 'flex',
},
})
Changing e.g. primary color in theme causes new run makeStyles, but the values of root and child are the same as before (shallow compare on root and child). A component using these useStyles should not be rendered, the MUI internals should swallow this change of theme which has no impact on this component.
const useStyles = makeStyles(theme => {
root: {
padding: theme.palette.primary.main,
},
child: {
display: 'flex',
},
})
Changing primary color in theme make root differ from previous run. The child may stay the same. The root class has changed, a component render must be triggered.
Motivation 🔦
I developed a quite complicated API visualizer with lot of rows, boxes, values, icons etc.; the DOM is really non-trivial. I provide a dark/light switcher. A use makeStyles / useStyles in virtually every component. Changing the theme from light to dark or vice versa has direct impact on few components; almost all makeStyles use only theme.spacing which I don't touch. Switching the theme causes that virtually all component must be recomputed, it's really slow in dev mode, and noticeable in prod mode.
If there was even a trivial optimization in makeStyles / useStyles (shallow compare on class objects), then changing of theme could be really fast, now it's lagging as whole application must be rendered again.
Summary 💡
A common style of getting class names for
classNameprop is the following pattern:The Material UI app is wrapped in
ThemeProvidercontext. A component usesuseStylesas follows:Changing theme object (via
setTheme) causes that allmakeStylescallbacks run with newtheme, and it generates new set of classes used by application. The components are rerendered so that they read new class names inclassesand React will then propagate the changes to browser DOM.It looks that
useStyleshook causes component to render even if there is no real change in class content. Let's take the examplemakeStylesabove. If I can change e.g. a primary color in a theme, new run ofmakeStyleswill return the same as before:root: { padding: 8 }. A component usinguseStylescould stay the same, there is no need to create new class name and rerender the component.Proposal: At least some trivial memoizing should be added to
makeStyles, so that ifthemeis changed, but a class returned bymakeStyleshas the same value, the class should stay the same; if all classes frommakeStylesresult are the same as before, a component usinguseStylesshould not rerender.Examples 🌈
Changing e.g. primary color in theme causes new run
makeStyles, but the values ofrootandchildare the same as before (shallow compare onrootandchild). A component using theseuseStylesshould not be rendered, the MUI internals should swallow this change of theme which has no impact on this component.Changing primary color in theme make
rootdiffer from previous run. Thechildmay stay the same. Therootclass has changed, a component render must be triggered.Motivation 🔦
I developed a quite complicated API visualizer with lot of rows, boxes, values, icons etc.; the DOM is really non-trivial. I provide a dark/light switcher. A use
makeStyles/useStylesin virtually every component. Changing the theme from light to dark or vice versa has direct impact on few components; almost allmakeStylesuse onlytheme.spacingwhich I don't touch. Switching the theme causes that virtually all component must be recomputed, it's really slow in dev mode, and noticeable in prod mode.If there was even a trivial optimization in
makeStyles/useStyles(shallow compare on class objects), then changing of theme could be really fast, now it's lagging as whole application must be rendered again.