React Loading in Stylesheet only when Component is loaded - javascript

I have an App Component that does all my routing for my project, where I import all the necessary components.
import React from "react";
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import './App.scss';
import Login from "../../login/Login";
import Overview from "../../overview/Overview";
import SubNav from "../../subnav/SubNav";
import ForgotPassword from "../../forgot-password/ForgotPassword";
const App = () => {
return (
<div className="App">
<Router>
<div className="App-container">
<Switch>
<Route path="/login" component={Login} exact />
<Route path="/forgotpassword" component={ForgotPassword} exact />
<Route path={"/"} component={SubNav} />
</Switch>
<Route exact path={"/"} component={Overview} />
<Route path={"/overview"} component={() => <Overview />} />
</div>
</Router>
</div>
);
}
export default App;
For example, in my Login component, I have the following imports...
import React from 'react';
import './Login.scss';
import LoginBenefits from './LoginBenefits';
import LoginFormContainer from './LoginFormContainer';
The issue I am having here with the import of the Login.scss
In this file I do imports of specific other scss files that are related to the Login Component. Say, for example, I had one that styled a class called .Tabs
#import "../../scss/_variables";
$Tabs-padding: 15px;
#import "../tabs/Tabs.scss";
.Login {....
Now for example, if in the ForgotPassword Component, if I were to add a div with a className of Tabs it would then style it correctly. This isn't what I want, it means that whatever is imported in the Login component gets loaded throughout the whole project, which means I cannot override any SASS variables without having to import the same SASS file again and makes the webpack bundled css file larger than it needs to be.
I guess my question is, how do I contain the Login.scss to only import when the Login component actually renders?
Or am I going about the whole imports in the wrong way?

What you have to understand is, when you import your scss files. They get converted to css and are rendered as 'internal styles' in the app. Basically they become global css rendered in the header. So unless you use scss properly and structure your css with a hierarchy you cannot achieve containment!
But what you have stumbled upon is an intriguing idea, which has
pushed the community to come up with a solution called css in js!
Look at this video!
The basic idea is to bring css into the React Component containing the styles inside the component. It is achieved using using template strings. This is groundbreaking because you now how the full power of javascript behind you to manipulate css!
This is an exhaustive list of frameworks that can help you with this. styled-components is the most widely adopted framework. But you can take a pick!
This is an example of how your code will look
import React from 'react';
import { render } from 'react-dom';
import styled from 'styled-components';
const Container = styled.div`
text-align: center;
`;
const Button = styled.button`
background-color: #ff0000;
width: 320px;
padding: 20px;
border-radius: 5px;
border: none;
outline: none;
&:hover {
color: #fff;
}
&:active {
position: relative;
top: 2px;
}
#media (max-width: 480px) {
width: 160px;
}
`;
const App = () => (
<Container>
<Button>Click me!</Button>
</Container>
);
render(<App />, document.getElementById('content'));
And styled components takes care of containing your css to the relevant component!

You need to bundle the all your scss file into single file. You can do this in webpack config file with use of ExtractTextPlugin
module: {
rules: [{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: ['css-loader', 'sass-loader']
}),
},
{
test: /js$/,
exclude: /(node_modules)/,
loader: "babel-loader",
}
]
},
plugins: [
new ExtractTextPlugin({
filename: "dist/assets/css/style.bundle.css"
})
]

Related

React components not rendering when routing to new page with react-router-dom v6

I am trying to set up routing in my React app. I am not getting any error and the app is not breaking but when I navigate to a new page nothing is displayed. I am using react-router-dom v6 and 'Switch' has been replaced with 'Routes' and component has been replaced with element: https://reacttraining.com/blog/react-router-v6-pre/. It also appears you do not need the leading "/".
EDIT at bottom of page.
http://localhost:3000/Player and http://localhost:3000/* (or anything other than the * ) both render blank screens.
This is the landing page which works fine:
HomePage.tsx
/** #jsxImportSource #emotion/react */
import React from 'react';
import { css } from '#emotion/react';
import logo from '../assets/cyberpunk.png';
export const HomePage = () => (
<div
css={css`
margin: 10px auto 20px auto;
padding: 30px 20px;
max-width: 1000px;
display: flex;
align-items: center;
justify-content: space-between;
`}
>
<div>
<img
src={logo}
alt="Logo"
css={css`
width: 700px;
margin-left: 130px;
`}
/>
<h2>Players</h2>
<button>Select a toon</button>
</div>
</div>
);
This is the player page:
PlayerPage.tsx
import React from 'react';
export const PlayerPage = () => <h2>"One toon"</h2>;
The page not found page:
NotFoundPage.tsx
import React from 'react';
export const NotFoundPage = () => <h2>"Page Not Found"</h2>;
Finally,
App.tsx
/** #jsxImportSource #emotion/react */
import React from 'react';
import { css } from '#emotion/react';
import { Header } from './header';
import { HomePage } from './Views/HomePage';
import { fontFamily, fontSize, gray2 } from './Styles';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { PlayerPage } from './Views/PlayerPage';
import { PlayersPage } from './Views/PlayersPage';
import { PlayerCreatePage } from './Views/PlayerCreatePage';
import { NotFoundPage } from './Views/NotFoundPage';
function App() {
return (
<BrowserRouter>
<div
css={css`
font-family: ${fontFamily};
font-size: ${fontSize};
color: ${gray2};
`}
>
<Header />
<Routes>
<Route path="" element={<HomePage />} />
<Route path="Players" element={<PlayersPage />} />
<Route path="Player" element={<PlayerPage />} />
<Route path="Create" element={<PlayerCreatePage />} />
<Route path="*" element={<NotFoundPage />} />
</Routes>
</div>
</BrowserRouter>
);
}
export default App;
Why would the h2 elements in the NotFoundPage and PlayerPage not be being displayed? It acts like I'm navigating to an incorrect route every time.
I fixed it kind of. I remade one of the pages to look like this:
function PlayerCreatePage() {
return (
<div style={{ padding: 20 }}>
<h2>About View</h2>
<p>Lorem ipsum dolor sit amet, consectetur adip.</p>
</div>
);
}
export default PlayerCreatePage;
And this one does show up. Why is that? What is wrong with the other views?
I tried to recreate your error but was unable to. At first, I thought it might be an issue with you not writing return() inside the functions but then I realised you have exported without curly braces, so return isn't necessary. Anyway, the code runs fine, you should have tried to recreate in a new environment. Peace!
Issue is in the App.tsx file, change the element prop to component, move the generic route to the bottom and add exact
in front of specific routes.
see the below changes :- `
/** #jsxImportSource #emotion/react */
import React from 'react';
import { css } from '#emotion/react';
import { Header } from './header';
import { HomePage } from './Views/HomePage';
import { fontFamily, fontSize, gray2 } from './Styles';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { PlayerPage } from './Views/PlayerPage';
import { PlayersPage } from './Views/PlayersPage';
import { PlayerCreatePage } from './Views/PlayerCreatePage';
import { NotFoundPage } from './Views/NotFoundPage';
function App() {
return (
<BrowserRouter>
<div
css={css`
font-family: ${fontFamily};
font-size: ${fontSize};
color: ${gray2};
`}
>
<Header />
<Routes>
<Route exact path="/Players" component={<PlayersPage />} />
<Route exact path="/Player" component={<PlayerPage />} />
<Route exact path="/Create" component={<PlayerCreatePage />} />
<Route path="/" component={<HomePage />} />
<Route path="*" component={<NotFoundPage />} />
</Routes>
</div>
</BrowserRouter>
);
}
export default App;
`
it will work.

Next.js Flashing with Ant Design on Chrome

I am currently developing a website utilizing Next.js and Ant Design and I have found a Chrome only issue that I am unable to fix. Whenever the user leaves the page or leaves the chrome window and returns, there is a brief flash of black on every page of the website. Furthermore, it seems that CSS styles are not being loaded fast enough, because when the website is reloaded, it is possible to see an enlarged version of my SVG logo before it is properly resized, which is very distracting. These issues only persist on Chrome to my knowledge as I have tested it with Safari and Firefox and have been unable to reproduce this issue. I have looked around for a solution, but they all use styled-components as well as a _document.js file in their project to solve the issue, but I have neither currently. Any help would be great on this, the relevant code will be below, if anything else is needed I can provide more. (Not every bit is used, I did use a tutorial to set learn how next.js worked so there are remnants of that).
EDIT: I want to add that the css flash/black flash happens on refresh of the page or when the window is deselected or minimized. I am still unsure if this is a problem with Next.js or if it is a problem with my implementation of the global css file with Ant Design.
EDIT 2: This problem is still an issue and I have been still unable to fix it...It's not too serious but it is annoying for chrome users I have found when doing alpha testing.
_app.js
import '../styles/global.css'
import React from 'react'
import App from 'next/app'
import Head from 'next/head'
import { Provider } from '../contexts/countryContext'
//There is a chrome only issue where the CSS Elements flash for like half a second when the page is loaded, not sure how to fix.
export default class MyApp extends App {
render() {
const { Component, pageProps } = this.props;
return (
<div>
<Head>
</Head>
<Provider>
<Component {...pageProps} />
</Provider>
</div>
)
}
}
global.css
#import '~antd/dist/antd.css';
:root {
--primary-color: #8497f5;
--light-secondary: #A0AAEC;
--light-tertiary: #5467DE;
--dark-secondary: #474C69;
--dark-tertiary: #4554B5;
}
html,
body {
padding: 0;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu,
Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
line-height: 1.6;
font-size: 18px;
}
* {
box-sizing: border-box;
}
a {
color: #0070f3;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
img {
max-width: 100%;
display: block;
}
index.js
import {Layout, Row, Spin, Divider} from 'antd'
import {Component, useState, useContext} from 'react'
import Link from 'next/link'
import {Context} from '../contexts/countryContext'
import layout from '../styles/layout.module.css'
import utils from '../styles/utils.module.css'
import SiteHeader from '../components/siteHeader'
import CalculationCard from '../components/CalculationCard'
import CookieHeader from '../components/CookieHeader'
const { Header, Content, Sider, Footer } = Layout;
const Main = () => {
const context = useContext(Context)
return (
<Layout style={{backgroundColor:"white"}}>
<SiteHeader/>
<Content className={layout.container}>
<header className={layout.header}>
<Link href="countrySelector">
<img src={context.flag + ".png"} className={layout.headerImage}/>
</Link>
<h1 className={utils.heading2Xl}>{context.name}</h1>
</header>
<CookieHeader/>
</Content>
<Content>
<Row gutter={16}>
<Divider orientation="left" style={{fontSize: "1.15rem", lineHeight: 0}}>Economic</Divider>
<CalculationCard name={"Maintenance"} desc={"Land and Naval Mintenance"} img={"local_reg_cost_icon"} link="maintenance"/>
<CalculationCard name={"Development Cost"} desc={"Mana Costs for Development"} img={"dev_cost"}/>
</Row>
</Content>
{/* <Footer style={{height: "100%"}}>
Indev
</Footer> */}
</Layout>
);
}
export default Main;

React and React Router - A really very basic and simple Cookie Banner

I'm working on React applications. I need a really very simple Cookie banner. The one that informs that the website uses cookies. There are various (theoretically simple) solutions in npm packages, but they all cause some problems in my projects. I have the impression that they are overdesigned, although they are supposed to be simple.
My projects mainly based on React with React Router.
OK. We have React and React Router (react-router-dom). And we need:
react-cookie npm install react-cookie
react-modal npm install react-modal
bootstrap npm install bootstrap
ModalCookies.js component:
import React from 'react';
import {
Link
} from 'react-router-dom';
import { useCookies } from "react-cookie";
import Modal from 'react-modal';
import '../modal.css';
function ModalCookies() {
const [cookies, setCookie] = useCookies(["allowcookies"]);
function handleCookie() {
setCookie("allowcookies", true, { path: "/", expires: new Date(Date.now() + (100 * 24 * 60 * 60 * 1000)) });
}
function closeModal() {
handleCookie();
}
return (
<Modal isOpen={cookies.allowcookies ? false : true} className="Modal" overlayClassName="Overlay">
<h6>PRIVACY & COOKIES POLICY</h6>
<p className="text-justify">
I use cookies to personalize content, ads and to analyze the traffic.
I also share information about your use of my website with my social media,
advertising and analytics partners who may combine it with other information that you have provided to them or that they have collected from your use of their services.
If you continue browsing, it means that you accept the use of cookies on this website.
</p>
<div className="text-right">
<button
className="btn btn-secondary mr-2 mb-2"
onClick={closeModal}>
OK
</button>
<Link to="/privacy"
className="btn btn-outline-secondary mb-2"
onClick={closeModal}>
Learn More
</Link>
</div>
</Modal>
);
}
export default ModalCookies;
modal.css file:
.Modal {
position: absolute;
top: auto;
left: 15%;
right: 15%;
bottom: 15%;
border: 1px solid rgb(100, 100, 100);
background: rgb(255, 255, 255);
outline: none;
padding: 40px;
z-index: 1;
}
.Overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(255, 255, 255, 0.60);
}
The file that manages the main view of the application with React Router (for example: Home.js or App.js)(excerpt):
//...
import ModalCookies from './ModalCookies';
//...
</Route>
</Switch>
<ModalCookies />
<Footer />
</Router>
//...
index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import { CookiesProvider } from 'react-cookie';
import Modal from 'react-modal';
import App from './App';
import 'bootstrap/dist/css/bootstrap.css';
Modal.setAppElement('#root');
ReactDOM.render(
<React.StrictMode>
<CookiesProvider>
<App />
</CookiesProvider>
</React.StrictMode>,
document.getElementById('root')
);
It works very well in my projects. Any comments or questions are welcome.

CSS getting applied to all files even though not imported

I am dealing with 2 components:
header.js and footer.js.
I also have 2 css files:
header.module.css and footer.module.css.
Both of them use different styling for the a tag.
I import the respective CSS files within each js file, but the a styling in footer.module.css seems to overtake the styling in header.js even though it wasn't imported.
Here is the code:
header.js
import React from "react"
import { Link } from "gatsby"
import "../styles/header.module.css";
const ListLink = props => (
<li style={{display: `inline-block`, marginRight: `1rem`, fontSize: '1.15rem', fontWeight: 'bold'}}>
<Link className="link" to={props.to}>{props.children}</Link>
</li>
)
footer.js
import React from "react"
import "../styles/footer.module.css";
const FooterLink = props => (
<li style={{ display: `inline-block`, marginRight: `1rem`, marginBottom:'0rem', fontSize: '1.05rem', fontWeight: 'bold'}}>
{props.children}
</li>
)
header.module.css
a {
color: var(--textLink);
text-shadow: var(--textShadow);
transition:.2s;
background-image: var(--bgimage);
}
a:hover {
color: #da1e11;
background-image: none;
}
footer.module.css
a{
color: var(--textLink);
text-shadow: var(--textShadow);
transition:.2s;
background-image: none;
}
a:hover {
color: #da1e11;
background-image: none;
}
The background-image property from footer overtakes the one specified in header.
If you are using Gatsby's default <Layout>, it shares <Header> and <Footer> components so, both are loading each CSS in each page as you can see here:
return (
<>
<Header siteTitle={data.site.siteMetadata.title} />
<div>
<main>{children}</main>
<Footer>
© {new Date().getFullYear()}, Built with
{` `}
Gatsby
</Footer>
</div>
</>
)
}
The easiest solution is to wrap the each component in a class to make the CSS only available inside that class, something like this:
import React from "react"
import { Link } from "gatsby"
import "../styles/header.module.css";
const ListLink = props => (
<li className="list__item">
<Link className="link" to={props.to}>{props.children}</Link>
</li>
)
Note: you can even wrap the <Link> inside a <div> for example.
I would suggest removing inline styles if you are using CSS modules to avoid mixing styles and improve readability.
The same applies for the <Footer> component.
According to the documentation it's import something from './something.module.css' and then <Component className={something.error}

Is it possible to activate a css class that effect the html tag depending on the route?

I'm creating a react site that ONLY in the home page ( " / " ) should have:
html{
overflow: hidden;
}
but when I move to any other page ( " /something " ) that css is active
(that css is in the home.css that is linked only in home.js)
All the following code is
App.js:
const App = () => {
return (
<Router>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/page" component={Page} />
</Switch>
</Router>
);
}
Home.js:
import './Home.css';
Home.css:
#media (min-width: 1024px) {
html {
overflow: hidden;
}
}
Pagge.js:
import './Page.css';
Page.css:
(nothing)
I expect the page "/" to use the css of Home.css and the other page to not use the Home.css
Your css imports aren't added and removed dynamically, they're all hoovered up and injected in to the <head> or bundled into a single css file when you build your bundle(s).
Adding or removing a style to your <html> tag as you navigate is possible but it is going to be messy. It will be far easier (and saner) to re-structure your app so that you can apply the overflow:hidden to a containing element on some pages but not others.
It cannot be achieved by css but you can use inline style like below:
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
function Home() {
return (
<div className="Home" style={{overflow: window.innerWidth >= 1024 ? 'hidden' : 'initial'}}>
<h1>Home </h1>
</div>
);
}
function Page() {
return (
<div className="Page" style={{overflow: 'initial'}}>
<h1>Page</h1>
</div>
);
}

Categories