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

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.
I "continue as guest", and new components are rendered. But notice the logo image, which now has new styling:
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.

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

I've faced this problem after migrating to the new material-ui version (5).
This should help you if you have the same issue
https://mui.com/guides/migration-v4/#migrate-from-jss
https://github.com/mui-org/material-ui/blob/master/packages/mui-codemod/README.md#jss-to-styled

Related

React App localhost:3000 logo not spinning

first ever post from me. Here it goes.
I have installed Visual Studio Code and wanted to create my first React app. I read through the documentation, used Syntax:
npx create-react-app my-react-app
Also used npm start
I get the Compiled successfully! message in the terminal. The http:localhost3000 page opens in a new tab. The React logo is displayed. For what ever reason the React logo is a static image for me. I edited text in the page's P tags and they update in real time. The Live Server extension seems to work as well.
Just about every tutorial on video has that logo spinning. My concern is not having React or even Visual Studio Code setup correctly from the beginning. I've tried uninstalling and reinstalling 3x now. I get the same static image.
Any thoughts, experiences, or even conspiracy theories? Does the React logo spin for you? or static like mine? Is there any way I can make it spin every time I create a new React App? Every time my code is not working (do to my code most likely) I keep thinking about the React Logo.
node version 14.16.0
npm 6.14.11
I also got the same static React logo and here is how I fixed it (on Windows VM)
Symptom:
When you try the tutorial on https://reactjs.org/docs/create-a-new-react-app.html,
an animation effect settings of Windows may prevent the React Logo from spinning,
try either (1) or (2)
(1) [How to fix and make the react logo spin -- by changing Windows system setting)
Go to Window's Advanced setting system setting -> Performance Options,
Check "Animate controls and elements inside windows"
(As soon as you check this setting and apply, you can see the react logo start spinning.)
(2) [remove the part that is affected in the code by the above setting] (fix from inside css code)
Remove line 10 " (prefers-reduced-motion: no-preference) " from src/App.css
for more details: https://developer.mozilla.org/en-US/docs/Web/CSS/#media/prefers-reduced-motion
Looks like method 2 always works no matter what animation settings you have on your system. But as a tutorial, you might want to avoid making changes to the original source code from the beginning.
Had the same problem and this worked:
In App.css, on line 10, delete the line containing " (prefers-reduced-motion: no-preference) " and the closing bracket 3 lines below it.
I had the same issue on Windows 10. Found this link: https://developer.mozilla.org/en-US/docs/Web/CSS/#media/prefers-reduced-motion
And used this line to get it working:
In Windows 10: Settings > Ease of Access > Display > Show animations in Windows
So as I said in the comments, no need to be concerned about the animated logo. Just an SVG file.
You can create your own as well Check here
Also, I generated a new project, and my logo spins.
First, check if you have the logo.svg file and then check
your App.css file.
#media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
#keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
Also, you need to have them imported on your App.js,
both .css and .svg
Delete only part ": no-preference" from line 10. It should be "#media (prefers-reduced-motion)", then the logo is spinning (at least mine).

Testing different fonts in a React project

Question
How to quickly test different fonts in a React project?
Overview
I'm learning how to use React/Gatsby with this template. In this example the site uses .sass files for styling and I see font-family: "slick" is referenced in the slider.sass file and reset.sass file has this entry:
body
font-family: Roboto, Helvetica, Arial, sans-serif
font-size: 16px
Desired outcome
I would ideally like to experiment as quickly as possible with lots of different combinations of fonts in this and other projects.
For example, I would like to try changing all fonts to something like this for titles/headers and this for everything else.
What have I looked at?
I've seen this from Gatsby founder kyleamathews but my guess is that it would clash with current sass configuration in this example.
I also see that variables can be used with sass and could potentially be used for testing different fonts in this project but I'm not sure exactly how.
Thanks for any help showing how I should approach this.
Let me kick my answer off with a warning:
Disclaimer: I do not recommend doing this in production. This is intended for testing font pairings locally.
Once you have chosen your fonts, I suggest hosting webfonts on your domain to avoid hitting a remote CDN. You could use classic #font-face declarations, or Kyle Matthew's typefaces packages, for example.
Now, what you basically want to do is to import fonts client-side, to make it easy to try them out without rebuilding your site.
1. Get a link to embed your fonts client-side
First, you'll need to get an embed link from your font hosting CDN (in your case, from Google Fonts). It will look like this:
https://fonts.googleapis.com/css2?family=Great+Vibes&family=Montserrat
2. Embed the fonts on your Gatsby site
To embed the link on your Gatsby site, you have two choices:
using <link>
You can add a font to your Gatsby app as an external client-side package. You would typically either customize html.js, or use react-helmet.
In your case, I see here that react-helmet already built into the starter you're using, so you would need to update layout.js like this:
<HelmetDatoCms
favicon={data.datoCmsSite.faviconMetaTags}
seo={data.datoCmsHome.seoMetaTags}
>
<link href="https://fonts.googleapis.com/css2?family=Great+Vibes&family=Montserrat&display=swap" rel="stylesheet">
</HelmetDatoCms>
Check out the README of gatsby-source-datocms to read more about the HelmetDatoCms component
using #import
You can import a remote font in CSS (or SASS):
#import url('https://fonts.googleapis.com/css2?family=Great+Vibes&family=Montserrat&display=swap');
This is already being used in your starter, the import is in reset.sass. You would simply need to update the URL with one that includes the fonts you want to try out.
In your case, I would recommend the second option. You'll only need to edit a single file, which will make testing several fonts faster.
3. Use the fonts in your CSS
Third, no matter if you chose the <link> or the #import option, you'll need to update your CSS to use the fonts you've imported. As you mentioned already in your question, this is where is happens.
You'll want something like this:
body {
font-family: 'Montserrat', sans-serif;
}
h1, h2, h3 {
font-family: 'Great Vibes', cursive;
}

Including a css file in a React project

I am trying to use material UI with react.
On this website: https://jamesmfriedman.github.io/rmwc/installation
It says
material-components-web should be installed automatically as a peer dependency. Include node_modules/material-components-web/dist/material-components-web.min.css in your project via your method of choice (using a link tag, a css-loader, etc.).
But I am not sure what this actually means. How and where do I have to import that file to use this library?
At first, you should add the library to your project by running:
npm install --save rmwc or yarn add rmwc
Secondly, you should understand the following:
Generally speaking, Material Components Web library is actually a bunch of prebuilt design styles that you can link to your project to make it look Material.
The library that you are using, React Material Web Components [RMWC], is a React wrapper for the previous library. It means that it gives you a set of flexible React Components like <Button />, <TextField />, etc that are built in React and act in a virtual DOM.
It doesn't give any specific styling to the elements. Moreover, it is designed not to provide you any extra styling. To make your imported React components look Material, you should add the styling from the parent library [Material Components Web].
To add styling from that library, use the following:
Add it to your project:
npm install material-components-web or yarn add material-components-web
And then use the following line (use it once in your project):
import 'node_modules/material-components-web/dist/material-components-web.min.css';
RMWC does the ReactJS wrapping. The styling is still all done by MDC.
You can add the minified mdc css file to your project, but that will not give you much customization. I'd advise using sass for your project and importing that mdc modules there. This way you can change variables e.g. from primary color as explained here: https://github.com/material-components/material-components-web/tree/master/packages/mdc-theme
$mdc-theme-primary: #fcb8ab;
$mdc-theme-secondary: #feeae6;
$mdc-theme-on-primary: #442b2d;
$mdc-theme-on-secondary: #442b2d;
#import "#material/button/mdc-button";
A more in depth documentation on how to use styling specifically with RMWC can be found in the docu: https://jamesmfriedman.github.io/rmwc/styling
But overall you can either create your own classes you then apply to your elements such as buttons. E.g.
.my-button-style {
border-radius: 10px;
}
Or you override the mdc classes directly.
.mdc-button {
border-radius: 10px;
}
The mdc classes can be found in each of the package sites on GitHub. (e.g. for button: https://github.com/material-components/material-components-web/tree/master/packages/mdc-button)

CSS Reset with PostCSS autoreset

I'm trying out postCSS on a project using the create-react-app starter repo with postCSS and importing .css files for each component. That is, each component includes a import 'styles/componentA.css';, or several.
In order to create consistent styles across browsers I'd like to import a CSS reset. I've tried a few things:
Importing a .css file containing a standard CSS Reset based on Eric Meyer's reset.
Using the autoreset plugin for postCSS.
For the first option , in dev mode the CSS imports are added as <style> tags to the document. The CSS Reset appears last in the list of <style> tags, though it's imported in the top-level component. Ideally the CSS Reset would be imported first. Being last means it would overwrite any styles I apply to base elements (like h1 {font-size: 40px;})
For the 2nd option (using autoreset), it doesn't appear there's a way to apply specific rules to specific elements. For example, I want to apply list-style: none only to ul and ol elements.
Is it possible to use the autoreset plugin to do a Eric Meyer-like CSS Reset in postCSS? Or am I going in a completely wrong direction and misunderstanding the purpose of it?
I don't use react but I faced a similar issue when using components and resets alongside PostCSS (I'm building things as described here: http://ecss.io/chapter7.html). I didn't want a reset loaded for each component, just a global one as would be used traditionally.
Therefore, I went with a 'component' purely for 'globalCSS'. This is the first component that gets loaded and loads in the reset (and also global PostCSS variables and mixins) so subsequent components have access to them without redeclaring.
Is that an approach you could use/adapt?

Load different css on different pages

I'm trying to find a solution to this problem:
I'm using a template with different css includes based on page, ex:
Login uses login.css
Home uses home.css
If I load both css the login page is broken, because styles are overwritten by home.css
So I need to load or require login.css if the route or the component is Login and the other one when is Home.
If I load both webpack builds a global css with both files, and everything is broken...
I tried to require the css in componentDidMount, but I think that is not the way :)
Thanks in advance
It sounds like both these styles are quite specific to the pages, so why not simply namespace them?
Within your templates, have a .login/.home class, and use this as the namespace within the css. If you're using sass, this is as simple as wrapping all the sass in the class. Otherwise, you can go through and add the class to the beginning of all the elements/clases.
First of all, you shouldn't have any problems if you use different css classes for your views and just style the elements based on those classes.
The best way to load css in react is to do it by components, if you got a component login.jsx, in your styles folder (or whatever folder you're using to hold your styles) create a sass partial _login.scss and add the css selectors and styles for that given component, and do that for every component in your react application.
Then you just include those partials into a main.scss file and that's the file you want to load into your react app.
Here's an example of a main.scss file with some sass partials.
#import 'base/variables';
#import 'base/defaults';
#import 'components/login';
#import 'components/home';
That's a good and clean way to work with styles in react, of course you will need to configure your webpack in order to get sass to work in your application.
Take a look at this and this for more info.
This is a more generic approach to combine CSS files, without depending on technologies like SASS or reactjs.
I assume, if you combine the two CSS files, you are using Grunt or similar tool, to automate that task. So automatically updating the CSS files should be OK for you, even though they are from an external source and you want to use updated versions without making manual changes.
I also assume, you are using classes to style your pages, so there are no tag based styles in your CSS. Because you cannot rename the tags in the CSS file without braking it or make larger changes to your code.
If my assumptions are true, you could use something like grunt-css-prefix. It can add prefixes to your CSS classes for the login page, like in this snippet.
Original CSS file content:
.foo,
.bar,
h1 {
display: none;
}
CSS file content after running the Grunt script:
.login-foo,
.login-bar,
h1 {
display: none;
}
Just use the login-foo like class names in your Login-HTML and you are good to go.
For more details on how to use grunt-css-prefix, please have a look at https://www.npmjs.com/package/grunt-css-prefix.

Resources