Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React + Material-UI style classes from different components conflict when served statically

Issue: styles applied to class names generated by Material-UI / JSS are incorrectly changing when components are re-rendered.

Setup: I'm serving a React app (built with create-react-app) that uses Material-UI jss styling and a Rails back end. I'm not sure how relevant the Rails part is since the same thing happens when I open the build/index.html file directly on my local machine -- the Rails back end handles the root request to serve the static client files as presented here. In either case, the static build is created using npm run build, which runs react-scripts build (from create-react-app).

Example of the issue: I have an <img> element which is given className: {classes.logo}. When built, classes.logo is "jss3", which takes on the following correct CSS:

.jss3 {
    height: 50px;
    position: relative;
    // [...more]
}

This looks like this -- the <img> component is at the top left in the app header.

enter image description here

I "continue as guest", and new components are rendered. But notice the logo image, which now has new styling:

enter image description here

What happened? The <img> component now shows the following styling:

.jss3 {
    height: 2em;
    padding: 7px;
    overflow: scroll;
    position: relative;
}

This css comes from an entirely different style object from a different component:

// FileEntry.js

  fileEntry: {
    position: 'relative',
    padding: '7px',
    height: '2em',
    overflow: 'scroll',
  },

From logs, I've determined that both classes.logo in AppHeader.js and classes.fileEntry from FileList.js are given the name "jss3". So that explains why the styles changed -- a new component (<FileEntry) was rendered and it overwrote the "jss3" class styles.

So the root question at the moment is: why are both style elements given the conflicting name "jss3"? How can I avoid this with a static front-end app? (The issue also occurs when I follow the instructions from the blog post above to deploy to heroku.) I'd love an answer that still allowed me to host both client and back-end from a single running instance as I'm doing here, but if another deployment setup is the best answer then I'd love to learn how + why.

like image 967
Andrew Schwartz Avatar asked Jun 16 '19 14:06

Andrew Schwartz


1 Answers

The issue is related to using two different versions of a class name generator. Many ways to do this; in my case I was mixing an older version of material-ui/core/styles#withStyles with a newer material-ui/styles#makeStyles as I was refactoring class components to use hooks. By removing usage of the older core/styles#withStyles, I fixed the issue.

What happens is the two style classname generators don't know about each other, and create class names with simple indexes (e.g. jss3). At least, they do this for production builds, it seems there use more verbose component-name-based class names in dev builds, which explains why I was only seeing it when hosting statically.

Since the FileEntry component was not rendered until login, the jss3 class name was not generated by the second class name generator until after the login action, at which point the jss3 class was given updated styling, and the browser applied it to the existing jss3 elements as it is meant to do.

Some workaround solutions involved forcing both to use the same Jss Provider, but not using independent invocations of class name generators in the first place was a more thorough and well-supported solution.

Similar issues are documented here:

  • https://github.com/mui-org/material-ui/issues/8223
  • https://github.com/mui-org/material-ui/issues/11628
like image 174
Andrew Schwartz Avatar answered Oct 23 '22 17:10

Andrew Schwartz