Skip to content

CSS styles duplication when using computed class names #24748

@yanickrochon

Description

@yanickrochon
  • The issue is present in the latest release.
  • I have searched the issues of this repository and believe that this is not a duplicate.

Current Behavior 😯

When creating CSS classes dependents on passed props values, the styles are duplicated when the component refreshes.

Expected Behavior 🤔

The styles should properly be updated, removing any duplicates and unused by previous calls to makeStyles.

Steps to Reproduce 🕹

See provided sandbox

Declaring styles like this will create duplicates every time the component using the styles refresh :

const useStyles = makeStyles((theme) => ({
  testElement: ({ index, bgColor }) => ({
    [`& div:nth-child(${index})`]: {
      backgroundColor: bgColor
    },
    [`& div:not(:nth-child(${index}))`]: {
      backgroundColor: theme.palette.common.white
    }
  })
}));

Context 🔦

I noticed this behavior when debugging some styles I use in a project to render striped tables. The class renders custom striped tables given certain parameters.

Actual rules being applied
/**
 * Make table rows alternate in color. By default, every even row will have an alternate color.
 * 
 * Usage : 
 * 
 *   const useStyles = makeStyles(theme => ({
 * 
 *     table: {
 *       ...themedTableRows(theme(theme)
 *     }
 * 
 *   }));
 * 
 * 
 * Ex:  themedTableRows(theme, 1, 0)     // defaults
 *         - row
 *         - alternate row
 *         - row
 *         - alternate row
 * 
 * Ex:  themedTableRows(theme, 2)
 *         - row
 *         - row
 *         - alternate row
 *         - alternate row
 *         - row
 *         - row
 *         - alternate row
 *         - alternate row
 * 
 * Ex:  themedTableRows(theme, 3, 1)
 *         - row  (skipped)
 *         - row  (skipped)
 *         - row  (skipped)
 *         - row
 *         - row
 *         - row
 *         - alternate row
 *         - alternate row
 *         - alternate row
 *         - row
 *         - row
 *         - row
 *         - alternate row
 *         - alternate row
 *         - alternate row
 * 
 * @param {Object} theme          Material UI palette
 * @param {Number} groupSize      the number of rows to alternate
 * @param {Number} offset         skip the number of first groups
 * @return {Object}               classes to extend a rule with
 */
export const themedTableRows = (theme, groupSize = 1, offset = 0) => ({
   [groupSize < 2 ? '&:nth-of-type(even)' : Array.from({ length: groupSize }, (_, k) => `&:nth-child(${groupSize * 2}n+${k + groupSize + 1 + (offset * groupSize)})`).join(',')]: {
      backgroundColor: theme.palette.type === 'dark' ? darken(theme.palette.action.hover, 0.5) : lighten(theme.palette.action.hover, 0.4),
   },
   '&.Mui-selected': {
      backgroundColor: theme.palette.type === 'dark' ? darken(theme.palette.secondary.dark, 0.7) : lighten(theme.palette.secondary.light, 0.6),
   },
   [groupSize < 2 ? '&.Mui-selected:nth-of-type(even)' : Array.from({ length: groupSize }, (_, k) => `&.Mui-selected:nth-child(${groupSize * 2}n+${k + groupSize + 1 + (offset * groupSize)})`).join(',')]: {
      backgroundColor: theme.palette.type === 'dark' ? darken(theme.palette.secondary.dark, 0.65) : lighten(theme.palette.secondary.light, 0.4),
   }
});

I was adding :hover styles when I noticed the multiplication of overrides in the developer console.

Your Environment 🌎

`npx @material-ui/envinfo`
 System:
    OS: Linux 5.4 Ubuntu 20.04.1 LTS (Focal Fossa)
  Binaries:
    Node: 14.5.0 - ~/.nvm/versions/node/v14.5.0/bin/node
    Yarn: 1.22.10 - ~/.nvm/versions/node/v14.5.0/bin/yarn
    npm: 6.14.5 - ~/.nvm/versions/node/v14.5.0/bin/npm
  Browsers:
    Chrome: 88.0.4324.96
    Firefox: 85.0
  npmPackages:
    @material-ui/core: ^4.11.3 => 4.11.3 
    @material-ui/lab: ^4.0.0-alpha.57 => 4.0.0-alpha.57 
    @material-ui/pickers: ^4.0.0-alpha.12 => 4.0.0-alpha.12 
    @material-ui/styles:  4.11.3 
    @material-ui/system:  4.11.3 
    @material-ui/types:  5.1.0 
    @material-ui/utils:  4.11.2 
    @types/react:  16.9.50 
    react: ^16.13.1 => 16.13.1 
    react-dom: ^16.13.1 => 16.13.1 

Metadata

Metadata

Assignees

No one assigned

    Labels

    scope: stylesSpecific to @mui/styles. Legacy package, @material-ui/styled-engine is taking over in v5.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions