Wrong Global SCSS/CSS Being Used - next.js

I have a Next.js app with two "layout" components:
/layouts/default-layout.tsx:
import { Footer } from '../components/footer';
import { Header } from '../components/header';
import './default-layout.scss';
export const DefaultLayout: React.FC = ({ children }) => (
<div className="d-flex flex-column vh-100">
<Header className="flex-shrink-0 fixed-top" />
<main className="flex-shrink-0">
{children}
</main>
<Footer className="mt-auto" />
</div>
);
/layouts/profile-layout.tsx:
import Helmet from 'react-helmet';
import 'bootstrap/scss/bootstrap.scss';
import './profile-layout.scss';
export const ProfileLayout: React.FC = ({ children }) => (
<div>
<Helmet
link={[
{ rel: 'stylesheet', href: 'https://fonts.googleapis.com/css?family=Poppins|Open+Sans|Dancing+Script&display=swap' },
]}
/>
{children}
</div>
);
Both layout components import some global SCSS styles.
Pages use one layout or the other like this:
const IndexPage: NextPage = () => (
<DefaultLayout>
{/* more content here */}
</DefaultLayout>
);
Most pages use the default layout, but my dynamic pages at /pages/profiles/[id].tsx use the profile layout. Navigating between pages works fine and each page uses the correct layout and correct SCSS files.
But if I type a page directly into the web browser's address bar, I get inconsistent results. Often the wrong SCSS file is used. Having the app open in another tab and navigating around seems to effect it too.
How can I have the correct SCSS styles loaded consistently?

Related

Kabab case CSS classes in Next.js [duplicate]

I am using SCSS modules for my components in React/Next.js but I can't figure out how to import kebab-case classes.
At the moment, I am just writing all my SCSS classes in camelCase but this isn't ideal as this means I cannot make use of SCSS cascading.
(I'm still learning React am I'm not so great at making dynamic components myself so I am sticking to React Strap for now.)
Essentially, I want to write
.company-logo
instead of:
.companyLogo
EDIT: className={styles['company-logo']} causes an unexpected token error
Here is my Component:
import styles from './styles/Navbar.module.scss'
const NavComponent = (props) => {
const [isOpen, setIsOpen] = useState(false);
const toggle = () => setIsOpen(!isOpen);
return (
<div>
<img src="../ss-logo.png" alt="Logo" className={styles.companyLogo}/>
</div>
);
}
export default NavComponent;
And my SCSS:
.companyLogo {
height: 3rem;
}
className={styles['company-logo']}
should be what you want.
You can use the object key [] syntax.
<img src="..." className={styles['company-logo']}`
<img src="../ss-logo.png" alt="Logo" className={`${style['company-logo']}`}/>
inline:
<img src="../ss-logo.png" alt="Logo" className={`${styles["company-logo"]}`}/>
variable:
var logo = classNames({
[`${styles["company-logo"]}`]: true,
});
return (
<div>
<img src="../ss-logo.png" alt="Logo" className={logo}/>
</div>
)

My Link with href doesn't scroll even though the link changes. Nextjs

I'm working on a react with nextjs project.
I'm using Link to scroll to a specific section on the same page.
Here is one of the components that use Link:
import styles from './section1.module.scss';
import Image from 'next/image';
import Button from '#material-ui/core/Button';
import tought_process from '../../../public/thought_process.png';
import Link from 'next/link';
const Section1 = () => {
return (
<div className={styles.container}>
<div className={styles.left}>
<div className={styles.leftContainer}>
<Link href='#enews'>
<div className={styles.buttonContainer}>
<Button className={styles.buttonstyle1}>Get started</Button>
</div>
</Link>
</div>
</div>
<div className={styles.right}>
<Image
src={tought_process}
className={styles.imageStyle}
alt='how to think about organizing'
layout='responsive'
priority
/>
</div>
</div>
);
};
export default Section1;
And here i mark the element with the id:
<div {...handlers} className={styles.bigBody}>
<NavBar open={menuOpen} toggle={setMenuOpen} scrollY={scrollY} />
<SideMenu open={menuOpen} toggle={setMenuOpen} scrollY={scrollY} />
<div className={styles.sections}>
<Section1 />
<Section2 />
<Section3 id='enews' />
<Section4 />
</div>
Can't figure out what i'm doing wrong.
Multiple clickable elements are wrapping each other. Remove the button and add the anchor element.
<Link href="#enews">
<a>Get started</a>
</Link>
<Link href="#enews">
<a className={styles.buttonContainer}>
<span className={styles.buttonstyle1}>Get started</span>
</a>
</Link>
I'd recommend updating the styles so you can remove the inner span element.
I use a custom link component that does a few things (not shown); one is smooth scroll to hash routes if the browser supports smooth scrolling (not Safari).
import NextLink, { LinkProps } from "next/link";
import { HTMLProps, MouseEvent, FC } from "react";
export const Link: FC<LinkProps & HTMLProps<HTMLAnchorElement>> = ({ as, children, href, replace, scroll, shallow, passHref, ...rest}) => {
const onClick = (event: MouseEvent<HTMLAnchorElement>) => {
if (href.startsWith("#")) {
event.preventDefault();
const destination = document.getElementById(href.substring(1));
if (destination) destination.scrollIntoView({ behavior: "smooth" });
}
};
return (
<NextLink as={as} href={href} passHref={passHref} replace={replace} scroll={scroll} shallow={shallow}>
<a href={href} {...rest} onClick={onClick}>
{children}
</a>
</NextLink>
);
};
I removed new lines to condense the code block
If you went with the above approach, don't include the anchor tag since it's automatically included.
import { Link } from "./custom/path/link"
<Link href="#enews">Get started</Link>
Two points here:
As per the nextjs, passHref has to be used if a custom element is used as a child of Link tag instead of an anchor tag.
As per the same docs value of href should be '/#enews' not '#enews'

React router dom links are not scrolling to the correct section of the page (not scrolling at all)

I'm having an issue where my navigation bar created with React-router-dom is not "scrolling/taking" me to the right place in the page, in fact, it is not taking me anywhere at all. This is a single page app
This is my App component where I set the Router and the paths of each component
import React, { useState, useReducer } from 'react'
import Footer from './Components/Footer';
import HeroSection from './Components/HeroSection'
import AboutMe from './Components/AboutMe';
import Projects from './Components/Projects';
import Modal from './Components/Modal';
import Form from './Components/Form'
import ScrollTop from './Components/ScrollTop';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
import NavBar from './Components/NavBar'
function App() {
const [show, setShow] = useReducer((p) => !p, false);
const [data, setData] = useState()
const handleData = (newData) => setData(newData)
return (
<div>
<Router>
<NavBar/>
<Switch>
<Route path='/aboutme' component={AboutMe}/>
<Route path='/projects' component={Projects}/>
<Route path='/contact' component={Form}/>
</Switch>
</Router>
<HeroSection/>
<AboutMe/>
<Projects setData={handleData} setShow = {setShow}/>
<Modal data={data} show={show} setShow={setShow} />
<Form/>
<ScrollTop></ScrollTop>
<Footer/>
</div>
)
}
export default App;
This is my NavBarwhere I set up the Links
import React, {useState} from 'react'
import {Link} from 'react-router-dom'
import * as FaIcons from 'react-icons/fa'
import * as AiIcons from 'react-icons/ai'
import {NavBarData} from './NavBarData'
const NavBar = () => {
const [sideBar, setSideBar] = useState(false)
const showSidebar = () => {
setSideBar(!sideBar)
}
return(
<>
<div className="navbar">
<Link to="#" className="menuBars">
<FaIcons.FaBars onClick={showSidebar}/>
</Link>
</div>
<nav className={sideBar ? "navMenuActive" : "navmenu"}>
<ul className="navMenuItems">
<li className="navbarToggle">
<Link to="#" className="menuBars">
<AiIcons.AiOutlineClose/>
</Link>
</li>
{NavBarData.map((item, index) => {
return(
<li key={index}>
<Link to={item.path}>
<span>{item.title}</span>
</Link>
</li>
)
})}
</ul>
</nav>
</>
)
}
export default NavBar
I have a separate file NavBarData where I store the data for each link
export const NavBarData = [
{
title: "About Me",
path: "/aboutme"
},
{
title: "Projects",
path: "/projects"
},
{
title: "Contact",
path: "/contact"
},
]
I have created a miniversion in codesandbox which kind of works frustrating enough but I still can't understand what I am doing wrong.
https://codesandbox.io/s/modest-currying-3o9oq?file=/src/App.js
🐛 Problem
Apparently, you are trying to scroll to a specific section using react-router-dom.
💡 Possible solutions
You can just use a HTML tag for that, using its href property with the section id.
💻 Code
sectionOne.js
function SectionOne() {
return (
<section id="sectionOne">
children
</section>
)
}
export default SectionOne;
NavBarData.js
export const NavBarData = [
{
title: "About Me",
path: "#sectionOne"
}
]
NavBar.js
function NavBar() {
return (
{NavBarData.map((item, index) => (
<li key={index}>
<a href={item.path}>
<span>{item.title}</span>
</a>
</li>
)}
)
export default NavBar;
💡 Extra tip
Using a dependency for this will just increase your bundle size, so unless it really has more than one specific route, it's not necessary to install.
Using the CSS property scroll-behavior: smooth, you can make the effect when the scrolling starts.
I finally find out why it wasn't working. Apparently in single page apps where you need to be scrolled to a certain point in the page rather than navigating, you are meant to use HashLink
I ran npm install --save react-router-hash-link and used a HashRouter in my App.js, going to leave the code here in case someday someone faces a similar issue.
App.js
import React, { useState, useReducer } from 'react'
import Footer from './Components/Footer';
import HeroSection from './Components/HeroSection'
import AboutMe from './Components/AboutMe';
import Projects from './Components/Projects';
import Modal from './Components/Modal';
import Form from './Components/Form'
import ScrollTop from './Components/ScrollTop';
import { HashRouter as Router, Route, Switch } from 'react-router-dom'
import NavBar from './Components/NavBar'
function App() {
const [show, setShow] = useReducer((p) => !p, false);
const [data, setData] = useState()
const handleData = (newData) => setData(newData)
return (
<div>
<Router>
<NavBar/>
<Switch>
<Route path='/aboutme' component={AboutMe}/>
<Route path='/projects' component={Projects}/>
<Route path='/contact' component={Form}/>
</Switch>
</Router>
<HeroSection/>
<AboutMe/>
<Projects setData={handleData} setShow = {setShow}/>
<Modal data={data} show={show} setShow={setShow} />
<Form/>
<ScrollTop></ScrollTop>
<Footer/>
</div>
)
}
export default App;
NavBar.js
import React, {useState} from 'react'
import {HashLink} from 'react-router-hash-link'
import * as AiIcons from 'react-icons/ai'
import * as FaIcons from 'react-icons/fa'
import {NavBarData} from './NavBarData'
const NavBar = () => {
const [sideBar, setSideBar] = useState(false)
const showSidebar = () => {
setSideBar(!sideBar)
}
return(
<>
<div className="navbar">
<HashLink to="#" className="menuBars">
<FaIcons.FaBars onClick={showSidebar}/>
</HashLink>
</div>
<nav className={sideBar ? "navMenuActive" : "navmenu"}>
<ul className="navMenuItems">
<li className="navbarToggle">
<HashLink to="#" className="menuBars">
<AiIcons.AiOutlineClose/>
</HashLink>
</li>
{NavBarData.map((item, index) => {
return(
<li key={index}>
<HashLink to={item.path} smooth>
<span>{item.title}</span>
</HashLink>
</li>
)
})}
</ul>
</nav>
</>
)
}
export default NavBar
EDIT:
For this to work you need to give the section/element you want to scroll to an id attribute and the HashLink to parameter will take /#idgiventoelement

Integrating modal component onto page on load React JS

I have webpage with React JS. The structure of site is MainContent.js --> Main.js -->ReactDOM render. I wanted to have modal popup when page opens so built modal component Modal.js--> DashModal.js which worked on its own project but not when imported to my site.
How do I import it correctly to have modal popup on load like it does on its own project? Thanks. I provided code below.
**Index JS**
import React from "react";
import ReactDOM from "react-dom";
import Main from "./containers/Main";
import { CookiesProvider } from "react-cookie";
import DashModal from "./components/DashModal"
// Import main sass file to apply global styles
import "./static/sass/style.scss";
ReactDOM.render(
<CookiesProvider>
<Main />
</CookiesProvider>,
document.getElementById("app")
);
**DashModal.js - the modal component**
import React from 'react'
import ReactDOM from 'react-dom'
import Modal from "../components/modal"
import "../components/modal.css"
import AppStore from "../static/images/AppLogoBlue.png";
class DashModal extends React.Component {
constructor(props) {
super(props)
this.state = {show:true}
}
showModal = () => {
this.setState({show: true});
};
hideModal = () => {
this.setState({show:false});
};
render() {
return(
<main>
<h1> React Modal </h1>
<Modal show = {this.state.show} handleClose ={this.hideModal}>
<div className = "left">
<a>
<img src={AppStore} alt= ""></img>
</a>
</div>
<div className = "left">
<button className= "button" onClick={this.hideModal}>Regular site </button>
</div>
</div>
</Modal>
<button type = "button" onClick = {this.showModal}>
open
</button>
</main>
);
}
}
const container = document.createElement("div");
document.body.appendChild(container);
ReactDOM.render(<DashModal/>, container);
export default DashModal;
**modal.js- part of modal which goes into DashModal.js**
import React from 'react';
import "./modal.css"
const Modal = ({ handleClose, show, children}) => {
const showHideClassName = show? "modal display-block" : "modal display-none"
return(
<div className={showHideClassName}>
<section style={ModalBox} className= "modal-main">
{children}
<button onClick={handleClose}>close</button>
</section>
</div>
);
};
export default Modal;
Thanks in advance
From my understanding, you want to open the modal by default when the <DashModal /> was imported into another component.
You can pass a prop show={true|false} to DashModal component <DashModal show={true} /> and inside that component add a componentDidMount lifecycle method
componentDidMount = () =>{
const {show} = this.props;
if(show){
this.showModal()
}
}
This will check the props and call the showModal when the component is loaded.

How to manage different css style for different layouts in react Js?

I have two different layouts for front End and for admin End.I am including css files in render function in both layouts but css conflicts in both layouts.
Layout for front End
import React, { Component } from "react";
import { Switch, Redirect, Route } from "react-router-dom";
import Header from "components/FrontEnd/Header/Header";
import Footer from "components/FrontEnd/Footer/Footer";
import Menu from "components/FrontEnd/Menu/Menu";
class Frontend extends Component {
render() {
require("../../assets/fonts/frontEnd.css");
return (
<div className="section-frontEnd">
<Header {...this.props} />
<div id="main-panel" className="" ref="mainPanel">
<Switch>
//Routes Swichting ...
</Switch>
<Footer />
</div>
</div>
);
}
}
export default Frontend;
Layout for Admin End
import React, { Component } from "react";
import { Switch, Redirect } from "react-router-dom";
import Header from "components/Admin/Header/Header";
import Footer from "components/Admin/Footer/Footer";
import Sidebar from "components/Admin/Sidebar/Sidebar";
class Dashboard extends Component {
render() {
require('bootstrap/dist/css/Admin.css')
return (
<div className="wrapper">
<Sidebar />
<div id="main-panel" className="main-panel" ref="mainPanel">
<Header />
<Switch>
//Routes Swichting ...
</Switch>
<Footer />
</div>
</div>
);
}
}
export default Dashboard;
Please suggest me a better solution for this problem.
Note:I am not using webpack file in my project.
Below is my folder structure.
For each page section Make one superclass and Write all CSS based on that. This method won't conflict the layouts.
Example:
.section-frontEnd #main-panel{
// code
}
.admin-frontEnd #main-panel{
// code
}

Resources