Hi, dear devs.
Thanks a ton for all the positive comments in the part 1/3 of our Trash Course. 😊
It motivates me to keep writing and researching even more in order to delivery high-quality content (or something close to it 😂) for you guys.
⭐⭐⭐⭐⭐ You all deserve the stars! ⭐⭐⭐⭐⭐
I know it is Friday 📅 so I promise don't waste your time here, ok? 😛
What will be covered in this part 2/3?
- Layouts,
- Adding styles (global stylesheets and CSS modules),
- Creating a customized Not Found page,
- Redirecting.
Part 5 - Layouts 🖼️
Let's imagine a scenario where there is a big application and we want to use both the Footer
and Navbar
components we created previously on it. It is possible to just drop them in every page component we need but besides than just repeating code, that is not something good (DRY), we will also make harder to track these components.
In order to avoid these kind of issues we can create layouts, wrap all the different pages with it and reuse the Layout
component through our application.
1- First step is to create the Layout
component in the components folder (/components/Layout.js
) and import the components that we will use to wrap all the children
.
import { Navbar } from './Navbar';
import { Footer } from './Footer';
const Layout = ({ children }) => {
return (
{/** We will style it later on :) */}
<div className="layout-content">
<Navbar />
{children}
<Footer />
</div>
);
};
export default Layout;
2- Second step is to wrap the page component(s) with the Layout we want to apply. In your case, the root component of the application /pages/_app.js
.
import '../styles/globals.css'; // SPOILER OF STYLING 👉👈
import Layout from '../components/Layout'; // We import the Layout
function MyApp({ Component, pageProps }) {
return (
<Layout>
{/** We wrap the root component with the layout.*/}
{/** and pass it as a children of the Layout component*/}
<Component {...pageProps} />
</Layout>
);
}
export default MyApp;
3- Third and the last step is to remove the already imported Footer and Layout Components in our home component pages/index.js
. (Otherwise they will be appearing twice. 👯♀️)
import Link from 'next/link';
export default function Home() {
return (
<div>
<h1>Hello Next.js</h1>
<Link href="/about">About</Link>
</div>
);
}
And that is it! Now the Layout (contaning Footer
and Navbar
) is rendering in every single page through our application. I know it is just React
stuff but "knowledge does not occupy space". ⚛️ 😃
Part 6 - Adding Styles 💅
The application is running fine but let's be honest here: It is horrible! 👹
As any web application, in Next.js
we can also add styles to it. There are n ways to do so as using global stylesheets
, styled JSX
, inline-style
, CSS modules
etc. We will learn about two of these methods now.
⚆ Global Stylesheets (styles/globals.css
)
This file holds the styles we can apply anywhere in your application. It seems logic I know, but I will point out the differences when between it and CSS modules
.
Important Note: We are here to learn about Next.js
and not how to master CSS styling so please don't judge. 😂
@import url('https://fonts.googleapis.com/css2?family=Quicksand:wght@300;400&display=swap');
:root {
--psy-blue: rgb(188, 152, 255);
--psy-teal: rgb(3, 129, 129);
}
* {
box-sizing: border-box;
}
html {
padding: 0;
margin: 0;
}
body {
font-family: 'Quicksand', sans-serif;
background-color: var(--psy-blue);
color: var(--psy-teal);
}
.container {
min-height: 65vh;
}
a {
color: var(--psy-teal);
text-decoration: none;
}
.layout-content {
max-width: 900px;
margin: 0 auto;
}
nav {
margin: 10px auto 80px;
padding: 10px 1px;
display: flex;
justify-content: flex-end;
align-items: flex-end;
border-bottom: 1px solid var(--psy-teal);
}
nav a {
margin-left: 10px;
}
nav .brand {
margin-right: auto;
}
footer {
display: block;
text-align: center;
padding: 30px 0;
margin-top: 60px;
color: var(--psy-teal);
border-top: 1px solid rgb(3, 78, 78);
}
If you are wondering: "Where the heck I have imported this file into the application?". It was not you, it was already there in the pages/_app.js
file. This line, this single line of code ... 👇
import '../styles/globals.css';
⚇ CSS modules
Allows us to write individual styles for each component. After created the stylesheets file we import it in whatever component needs it. Next.js
adds some random characters to the end of the classes / selectors names.
Example: in your browser (mouse left-click > "Inspect Element"
) you should see something like:
<div className="Home_container__2DbTr">...</div>
The ending __2DbTr
indicates the styles will apply only for this component so it avoids CSS conflicts
. You can think it as an unique id
.
We could have seem an example on the Home
component (/pages/index.js
) which had its own styles imported from the styles/Home.module.css
file, before we had cleaned up it. 😅
import styles from '../styles/Home.module.css';
Quick rules when add styling: ✏️🗒️
-
CSS Modules
must follow this class name convention:ComponentName
.modules
.css
. (e.g Home.modules.css) - How to use style:
If you have, for example, in your
module.css
file something like:
.title a {
color: #0070f3;
text-decoration: none;
}
You apply this style by:
import styles from '../styles/Home.module.css'; // 👈 Importing like mentioned previously
import Link from 'next/link';
export default function Home() {
return (
<div className="container">
<h1>Hello Next.js</h1>
<div className={styles.title}>
{/** 👆 applying the styles as shown*/}
{/** Remember the Link component creates an anchor tag in the DOM* 👇/}
<Link href="/about">About</Link>
</div>
</div>
);
}
Remember again that <Link>
in the DOM is just an <a>
tag.
🧧 Very Important Note: The selectors
must be pure selectors, in other words, you must use class selectors
instead element selectors
so using the following inside of your CSS module won't work so be aware of that.
a {
color: #0070f3;
text-decoration: none;
}
Part 7 - Custom 404 Page ❌😵💫
If you try to access a route that doesn't exist (e.g. http://localhost:3000/you-are-amazing
), Next.js
has a default 404 page
. Very often we want to customize our own.
Luckily, doing that is simpler than you may think.
Inside of the pages folder, we only need to create a 404.js
file and stylize that component using the techniques we have just learned.
import Link from 'next/link';
const NotFoundPage = () => {
return (
<div className="not-found-page">
<h1>Page Not Found</h1>
<p>Looks like this page went on vacation.</p>
<Link href="/">Home</Link>
</div>
);
};
export default NotFoundPage;
Now this customized Not Found
page replaces the Next.js
default one. I have also added some styling just because. 🙈
.not-found-page {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: rgb(221, 80, 15);
}
.not-found-page h1 {
font-size: 40px;
letter-spacing: 1.2rem;
}
.not-found-page p {
font-size: 26px;
}
.not-found-page a {
color: rgb(221, 80, 15);
box-sizing: border-box;
border: 1px solid rgb(221, 80, 15);
padding: 2px 20px;
background-color: rgb(183, 182, 255);
}
.not-found-page a:hover {
text-decoration: underline;
}
Part 8 - Redirecting ♺
Sometimes for some reason we need to automatically redirect an user to a determined page in the web site.
We can think in a situation where a lost user hit our Not Found Page
and we would like to redirect his/her to our Home
page, for example. Let's implement redirecting using both the React's useEffect
, Next's useRouter
hooks and the SetTimeout()
javascript function. (You need to admit, it has been a long time since you last used it, right? 🕰️)
So the new version of our 404 page will look like this:
import { useEffect } from 'react';
import { useRouter } from 'next/router'; // we import the router
import Link from 'next/link';
const NotFoundPage = () => {
const router = useRouter(); // initialize it
useEffect(() => {
setTimeout(() => {
router.push('/'); // and define where to redirect
}, 3000);
}, []);
return (
<div className="not-found-page">
<h1>Page Not Found</h1>
<p>Looks like this page went on vacation.</p>
<Link href="/">Home</Link>
</div>
);
};
export default NotFoundPage;
In short, the useEffect hook
will run only in the first rendering ([]
) of the component, trigger the setTimeout
to redirect to the Home
page (router.push('/')
) after 3 seconds (3000
).
Alright! That's it for the part 2/3. As I have promised in the beginning I wouldn't disturb to much so I tried to make it smooth.
What will be covered in this part 3/3? 🤔
- Static Assets, Custom Page Title and Metadata
- Fetching Data
- Dynamic Routes
Looks like there is just few topics remaining to be covered but believe me, they will consume a lot of your time. My aim here is that at the end of this series you will be able to build your own Next.js
applications.
For now, thanks a lot for following along until here. 🙏
If you could learn something new from these posts I am going to be really glad. Also if you have any doubt about what was covered until now, feel free to message me and I am going to try to explain the topic in a more understandable way. 😃
By the way, I answer all the comments. Not as fast as I wish but if you comment in any of my posts I guarantee you will be answered, soon or later. 🦄
You are free to go now! See you in the last part.
Have an amazing weekend and be safe! ❤️
Top comments (21)
Good stuff! One thing that I noticed as a privacy enthusiast:
Don’t use Google fonts, especially not as dynamic imports. This basically unwittingly injects Google trackers into your users web browser.
If you're using webpack there's a plugin that downloads the library on buildtime, that way you can still easily use google fonts without this privacy issue
Thanks, Christian.
I am going to definitively check it out too. ✍️
What the name of this plugin?
I was also unaware of this! I suppose it will be time to download the fonts and put them on my server. You can no longer trust anyone!
Check out the fontsource npm package
I feel the same, Jacob. Looks like Google and similars are literally everywhere. 😨
Thanks Mat! What could be the alternative to this?
I use fontsource.org and the associated npm package. It allows you to install specific fonts as dependencies and import them into your project as you would any other library.
My personal favorite is fontlibrary.org
Thanks again, Mat.
I was not aware of that at all. Thanks for the hint. I am at his exact moment researching more about the topic. 🕶️ 📚
sou retroeng Asm com +50 anos de experiencia, estudo e acompanho amo Next.js, uso Osso-oS sistema Gnu/Linux, sou novo aqui, onde esta o Trash Cource Parte 1/1, alguepode ajudar-me? exelente manual Vinicius, parabens!
50 anos de experiencia? Voce conheceu en pessoa o Jobs, Woz ou Gates? 😨
Temos muito o que aprender com programadores mais experientes, Chris.
Antes não tinha internet, nem Google, nem nada. Eles aprendiam na "raça", com livros e através da comunidade. 🤓
It's just that this statement surprised me and confused me actually! I know people got no internet readily available as now, and not demoting that fact, it just that the comment seems a little bit off IMHO
I got your point, Chris.
I am not making trouble or anything. Just trying to keep the comments section a friendly place to everybody. 😃
Have a nice weekend there!
Legal, Pimentel.
Se você publicar algum post relacionado a Assembly ou quiser compartilhar algo sobre, por favor me avise. Estou interessado em aprender mais sobre essa linguagem. 😊
Aqui deixo os links das três partes:
Part 1 / 3
Part 2 / 3
Part 3 / 3
Muito obrigado por acompanhar e interagir nos comentários.
Só clicar no link "Trash Course" no começo desse texto.
Valeu, André! 🤜 🤛
Great tutorial, Vinicius. I picked up Next for work and this is a clear guide to get started
Thanks for your comment, Adam. 😃
If you are interested I have just released the Part 3/3. It would be nice hear your opinion about it too. 🙏