DEV Community

loading...
Cover image for Next.js Trash Course - Part 2/3

Next.js Trash Course - Part 2/3

Vinicius Cerqueira Bonifácio
Self-taught MERN stack developer, technology passionate, Ruby on Rails admirer, Ubuntu evangelist, ex mountain guide, active football player, inactive surfer, professional backpacker and hitchhiker.
Updated on ・6 min read

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

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';
Enter fullscreen mode Exit fullscreen mode

⚇ 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>
Enter fullscreen mode Exit fullscreen mode

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';
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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! ❤️‍

Discussion (20)

Collapse
matjones profile image
Mat Jones

Good stuff! One thing that I noticed as a privacy enthusiast:

@import url('https://fonts.googleapis.com/css2?family=Quicksand:wght@300;400&display=swap');
Enter fullscreen mode Exit fullscreen mode

Don’t use Google fonts, especially not as dynamic imports. This basically unwittingly injects Google trackers into your users web browser.

Collapse
christiangroeber profile image
Christian Gröber

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

Collapse
vinicius77 profile image
Vinicius Cerqueira Bonifácio Author

Thanks, Christian.

I am going to definitively check it out too. ✍️

Collapse
tojacob profile image
Jacob Samuel G. • Edited

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!

Collapse
dayvista profile image
dayvista

Check out the fontsource npm package

Collapse
vinicius77 profile image
Vinicius Cerqueira Bonifácio Author

I feel the same, Jacob. Looks like Google and similars are literally everywhere. 😨

Collapse
singhrahul31 profile image
singhrahul31

Thanks Mat! What could be the alternative to this?

Collapse
dayvista profile image
dayvista

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.

Collapse
matjones profile image
Mat Jones

My personal favorite is fontlibrary.org

Collapse
vinicius77 profile image
Vinicius Cerqueira Bonifácio Author

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. 🕶️ 📚

Collapse
tupynamba profile image
Gwyra bebe pimentel

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!

Collapse
vinicius77 profile image
Vinicius Cerqueira Bonifácio Author

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.

Collapse
cmelgarejo profile image
Christian Melgarejo Bresanovich

50 anos de experiencia? Voce conheceu en pessoa o Jobs, Woz ou Gates? 😨

Collapse
vinicius77 profile image
Vinicius Cerqueira Bonifácio Author

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. 🤓

Thread Thread
cmelgarejo profile image
Christian Melgarejo Bresanovich

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

Thread Thread
vinicius77 profile image
Vinicius Cerqueira Bonifácio Author

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!

Collapse
andrelomba86 profile image
andrelomba86

Só clicar no link "Trash Course" no começo desse texto.

Collapse
vinicius77 profile image
Vinicius Cerqueira Bonifácio Author

Valeu, André! 🤜 🤛

Collapse
adam_zdrzalka profile image
Adam Zdrzalka

Great tutorial, Vinicius. I picked up Next for work and this is a clear guide to get started

Collapse
vinicius77 profile image
Vinicius Cerqueira Bonifácio Author

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. 🙏