DEV Community

loading...
Cover image for Next.js Beginner's Guide

Next.js Beginner's Guide

Eric The Coder
Businessman and blogger #Javascript, #Python and #PHP. My favorite frameworks/librairies are #React, #Laravel, and #Django. I am also a fan of #TailwindCSS
Updated on ・7 min read

Follow me!: Follow @EricTheCoder_


What is Next.js?

It's a React frontend development web framework that enables functionality such as server-side rendering and static site generation.

Server-side rendering?

In a traditional React app the entire app is loaded and rendered on the client. Next.js allow the first page load to be rendered by the server, which is great for SEO and performance.

Next.js other benefits

  • Easy page routing
  • server Api routes
  • Static site generation (like Gatsby)
  • Easy Deployment

Create Next.js first project

To install and create a Next.js projet you can use the handy node npx command 'create-next-app my-app-name'

$ npx create-next-app my-app-name
Enter fullscreen mode Exit fullscreen mode

Or with Tailwind CSS pre-configure

$ npx create-next-app -e with-tailwindcss my-app-name
Enter fullscreen mode Exit fullscreen mode

This will create a folder and create all files, configs and everything you need to start a Next.js app.

Once the app is created you can launch it

$ cd your-app-name
$ npm run dev
Enter fullscreen mode Exit fullscreen mode

This will launch your Next.js empty app. By default a welcome page is already created for you.

Pages and Routing

In Next.js to manage routes we dont have to use a routing library.

Next.js routing is very easy to implement.

When you create a new Next.js app with the create-next-app command, the app create by default a folder name 'pages'

This 'pages' folder is your routes management. So every react components file in the folder will be treated as a specific route.

For example, if the folder is containing those files:

  • index.js
  • about.js
  • blog.js

This file will automatically be converted in 3 routes:

  • The index page localhost/index
  • The about page localhost/about
  • The blog page localhost/blog

As you can see the principle is very easy.

Also, if you visit a route that dont exist like 'localhost/home' Next.js will automatically show a not found 404 page

Here an example of about.js page. Like you can see nothing is specified about the page. It is just a regular React functional component

function AboutPage() {
    return (
        <div>
            <h1>About</h1>
        </div>
    )
}

export default AboutPage
Enter fullscreen mode Exit fullscreen mode

Nested routes

How about nested routes like localhost/blog/contact?

To create nested routes you need to create a sub folder.

For example: pages/blog

Inside that folder you can create your 'contact.js' react component and that will create the page localhost/blog/contact

If you create a index.js file in that sub folder, Next.js will use that component to represent your root route. ex: localhost/blog will render pages/blog/index.js

If you create a file in pages/blog.js and another one under pages/blog/index.js. Both represent the same localhost/blog route. In that case Next.js will render only the blog.js file.

What about dynamic routes where each blog post have it's own route:

  • localhost/blog/my-first-blog
  • localhost/blog/my-second-blog-post

In Next.js you can create a dynamic route using the brackets notation.

For example: pages/blog/[slug].js

Yes that look a bit weird to include brackets to a file name but that's the way.

If slug variable can be extract from the route using the useRoute hook.

Here a example of the [slug].js page

import { useRouter } from 'next/router'

function PostPage() {
    const router = useRouter()
    return (
        <div>
            <h1>My post: {router.query.slug}</h1>
        </div>
    )
}

export default PostPage
Enter fullscreen mode Exit fullscreen mode

That's a basic example. In a real app, the slug variable will be use to load the post file or lookup in a database for the corresponding post.

Routes links

Now that you created your first route. I guess you are wondering how to link pages to those routes? To do that you need 'next/link'

Here a example of the home page with a link to the about page:

import Link from 'next/link'

export default function Home() {
  return (
    <div>
      <h1>Home</h1>
      <Link href="about">About</Link>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

In the about page, if you want to create a link to come back to the home page. You can type:

<Link href="/">Home</Link>
Enter fullscreen mode Exit fullscreen mode

If you want to style the link you have to use this syntax:

<Link href='/about'>
    <a className="text-blue-500">About this project</a>
</Link> 
Enter fullscreen mode Exit fullscreen mode

Route redirect

What if you want to force a redirect to a specific page? For example on a click of a button? You can use 'router.push' for that:

import Link from 'next/link'
import { useRouter } from 'next/router'

function About() {
  const router = useRouter()

  return (
    <div>
      <h1>About Page</h1>
      <p>This is the about page</p>
      <button onClick={() => router.push('/')}>Return to home</button>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

Where you put components?

Often you will want to create a components or a layout file. For example a component to render navbar.

Up until now we only have use the pages folder. What if you dont want your component to be a route page? You dont want user to go open page like: localhost/navbar

That's what will append if you put Navbar.js component inside the pages folder.

What to do in that case? Easy, you need to place all your 'not a page' components inside another folder.

By convention most Next.js use a folder name 'components' and this folder is created at the root folder of your apps.

So for example if you want to create a layout component you can do it in the new components folder: /components/Layout.js

That React component can be use anywhere in your app but will ne be reference as a route page.

Head compoment

Next.js server side render first page load. To do so it manipulate the html of you page. Including the header section.

To provide header section tag like title or meta you need to use the Next.js Head component.

Here's an example of a Layout component using the Head component.

// components/Layout.js
import Head from 'next/head'
function Layout({title, keywords, description, children}) {
    return (
        <div>
            <Head>
                <title>{title}</title>
                <meta name='description' content={description}/>
                <meta name='keywords' content={keywords}/>
            </Head>
            {children}
        </div>
    )
}

export default Layout

Layout.defaultProps = {
    title: 'This is my app title',
    description: 'This is my app description',
    keywords: 'web, javascript, react, next'
}
Enter fullscreen mode Exit fullscreen mode

Custom 404 not found page

It is possible to create a custom 404 not found page. You may want to personalize the message or include your own page layout.

Create 404.js file in the pages folder.

Next.js will then automatically redirect to this page when a 404 is encounter.

Here a example of a custom 404 page:

// pages/404.js
import Layout from '../components/Layout'

function NotFoundPage() {
    return (
        <Layout>
            Sorry the page you are looking is no where to be found.        
        </Layout>
    )
}

export default NotFoundPage
Enter fullscreen mode Exit fullscreen mode

Import shortcut alias

As your app grow more and more. Some components can be nested deep in your app folder structure.

import Layout from '../../components/Layout'
Enter fullscreen mode Exit fullscreen mode

It is possible to create a shortcut to help you save some key stroke and get a result like that:

import Layout from '@/components/Layout'
Enter fullscreen mode Exit fullscreen mode

The @ char is a shortcut syntax.

To create this shortcut and more you need to create a file name 'jsconfig.json' at the root of your app:

// jsconfig.json
{
    "compilerOptions": {
        "baseUrl": ".",
        "paths": {
            "@/components/*": ["components/*"],
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Server-side data fetching

Instead of fetching data on the client side, Next.js can
enables server-side rendering in a page and allows your to do initial data population, it means sending the page with the data already populated from the server.

To implement that server-side data fetching you have 2 options:

  1. Fetch data on each request
  2. Fetch data only once at build time (static site)

Fetch data on each request


To server-side render on each request you need to use the getServerSideProps function.

You can add this function at the end of your component file:

export async function getServerSideProps() {
  const res = await fetch(`http://server-name/api/items`)
  const items = await res.json()
  return {
    props: {items}, 
  }
}
Enter fullscreen mode Exit fullscreen mode

If that function is present in your component file, Next.js will automatically fill you component props with the getServerSideProps object.

Fetch data at build time


To server-side render at build time you need to use the getStaticProps function.

You can add this function at the end of your component file:

export async function getStaticProps() {
  const res = await fetch('http://server-name/api/items')
  const items = await res.json()
  return {
    props: {items}, 
  }
}
Enter fullscreen mode Exit fullscreen mode

You may also want to fetch data at build time but for a dynamic path (ex. /posts/my-first-post)

Let asume we have a page name posts/[slug].js

That will give you a routes of posts/my-first-post, posts/my-second-blog, etc.

In that situation you can use getStaticPaths to create all those sub routes at build time

export async function getStaticPaths() {
    const res = await fetch(`${API_URL}/posts`)
    const posts = await res.json()
    const paths = posts.map(post => ({params: {slug: post.slug}}))
    return {
        paths,
        fallback: true,
    }
}
export async function getStaticProps({params: {slug}}) {
    const res = await fetch(`${API_URL}/posts?slug=${slug}`)
    const posts = await res.json()
    return {
        props: {
            post: posts[0]
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Image optimization

Next.js has a built-in Image Component and Automatic Image Optimization.

The Next.js Image Component, next/image, is an extension of the HTML element, evolved for the modern web.

Images are lazy loaded by default. That means your page speed isn't penalized for images outside the viewport. Images load as they are scrolled into viewport.

First import the Image Component:

import Image from 'next/image'
Enter fullscreen mode Exit fullscreen mode

Use it in your component:

<Image
  src="/image.png"
  alt="Picture of the author"
  width={500}
  height={500}
/>
Enter fullscreen mode Exit fullscreen mode

If you want to know more about Next.js Image component you can read the official documentation: https://nextjs.org/docs/api-reference/next/image

Conclusion

That's it for today. I still have a lot of posts coming about React so if you want to be sure to miss nothing click follow me!

Follow me!: Follow @EricTheCoder_


Discussion (4)

Collapse
michaelcurrin profile image
Michael

Typo

-Gadsby
+Gatsby
Enter fullscreen mode Exit fullscreen mode
Collapse
michaelcurrin profile image
Michael • Edited

And these are better a plain strings unless you actually have something to interpolate inside it

-fetch(`http://server-name/api/items`)
+fetch('http://server-name/api/items')
Enter fullscreen mode Exit fullscreen mode
Collapse
michaelcurrin profile image
Michael

And this is bad grammar

-Many time you
+Often you
Enter fullscreen mode Exit fullscreen mode