Understanding Next.js: A Comprehensive Guide to the React Framework

Table of Contents

Introduction

What is Next.js

Getting Started

Next.js Basics

Pages and Routing

Dynamic Routes

API Routes

Styling in Next.js

Optimizations

References

Introduction

This guide will help you understand the fundamentals of Next.js, a powerful React framework designed for building modern web applications. Before diving into Next.js, it’s recommended to have a basic understanding of React and JavaScript. If you need to brush up on React, please check out our React page.

What is Next.js

Next.js is a React framework known for simplifying the development of React applications with a focus on server-side rendering, efficient routing, and improved developer experience. Its file-system-based router supports layouts, nested routing, loading states, and error handling. Next.js offers both client-side and server-side rendering, utilizing Client and Server Components for optimized rendering. The framework streamlines data fetching with async/await in Server Components and extends the fetch API for features like request memoization and data caching. Next.js supports various styling methods, including CSS Modules, Tailwind CSS, and CSS-in-JS. Furthermore it includes optimizations for images, fonts, and scripts to improve Core Web Vitals and user experience. For these reasons it is a popular choice for building full-stack web applications.

Getting Started

Make sure you have Node.js 18.17 or later. You can install the latest version of Node.js here.

To begin using Next.js, you need to set up a new project. To create a project run the following command:

npx create-next-app@latest

You will then see some prompts that ask for details of your application. Once this is completed, a new folder with your project name should be created!

If you need to install manually or for a more detailed guide, please follow the official guide on getting started with Next.js.

Next.js Basics

Once your Next.js project is set up, you can start exploring its basic features.

Components

Next.js utilizes React components. You can create components in the components directory and use them throughout your application. This is the same as with standard React apps. Here is an example of a simple component:

// components/MyComponent.js
import React from 'react';

const MyComponent = () => {
  return (
    <div>
      <p>This is a Next.js component!</p>
    </div>
  );
};

export default MyComponent;

Pages and Routing

One notable feature of Next.js is the automatic routing of pages. In Next.js, each file inside the pages directory becomes a route. For example, a file named About.tsx inside pages will be accessible at the /about route. This simple and intuitive routing system helps you structure your application without having to manually add routes like in standard React apps. Next.js eliminates this complexity by inferring routes from the file system, allowing you to focus on building components and pages rather than handling intricate routing logic.

Furthermore, Next.js supports dynamic routes, allowing you to create pages with dynamic content. For example, a file named [id].tsx inside pages/posts can match routes like /posts/1, /posts/2, and so on. This enables you to build flexible and dynamic applications. Here is an example directory tree with sample pages.

your-nextjs-project
|-- components
|   |-- MyComponent.js
|
|-- pages
|   |-- Home.tsx
|   |-- About.tsx
|   |-- Contact.tsx
|   |-- posts
|       |-- [id].tsx
|
|-- styles
    |-- main.css

Compare this to a traditional React app, where you would typically use additional libraries on top of manually defining routes. Here is an example of traditional React routing with the same pages as the above example (without the dynamic pages):

import React, {useEffect} from "react";
import "./App.sass";
import {Route, Routes} from "react-router-dom";
import Home from "./pages/Home";
import About from "./pages/About";
import Contact from "./pages/Contact";

function App() {

  return (
    <div className="app-wrapper-wrapper">
      <div className="app-wrapper">
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/about" element={<About />} />
          <Route path="/contact" element={<Contact />} />
        </Routes>
      </div>
    </div>
  );
}

export default App;

Optimizations

Code Splitting

Next.js excels in automatic code splitting, a crucial optimization technique. The framework divides your application code into smaller chunks, loading only the code required for the current page. This results in faster initial page loads and improved overall performance.

Server-Side Rendering (SSR) Optimizations

Next.js supports Server-Side Rendering, a powerful optimization that allows rendering pages on the server before sending them to the client. SSR enhances performance by reducing the client’s workload and ensuring that users receive pre-rendered content.

Built-in CSS and JavaScript Support

Next.js provides support for CSS and JavaScript, optimizing the loading and execution of these resources. With automatic handling of critical CSS and efficient bundling of JavaScript, Next.js ensures a streamlined and performant application.

Image Component Optimization

There are other small optimizations that you can implement in your code, for instance the Image component:

import Image from 'next/image'

Since the Image component extends the HTML <img> element, you can use the standard HTML attributes such as src, alt, etc. The Image component will automatically perform optimizations such as size optimizations, faster page loads, and visual stability.

There are many more optimizations the Next.js offers. To learn more, please visit the optimizing page on the official documentation.

API Routes

Next.js allows you to create API routes easily. By adding files to the pages/api directory, you can define serverless functions that handle API requests. This feature simplifies the development of server-side logic without the need for a dedicated server. Here is an example. Suppose you want to fetch posts from some external source. We can create a new file named post.js inside the pages/api directory:

export default async function handler(req, res) {
  try {
    const response = await fetch('https://some_external_source.com/posts');
    const posts = await response.json();

    res.status(200).json(posts);
  } catch (error) {
    console.error('Error fetching posts:', error);
    res.status(500).json({ error: 'Internal Server Error' });
  }
}

We can then have a component use this endpoint to fetch the posts:

import React, { useState, useEffect } from 'react';

const PostList = () => {
  const [posts, setPosts] = useState([]);

  useEffect(() => {
    const fetchPosts = async () => {
      try {
        const response = await fetch('/api/posts');
        const data = await response.json();
        setPosts(data);
      } catch (error) {
        console.error('Error fetching posts:', error);
      }
    };

    fetchPosts();
  }, []);

  return (
    <div>
      <h2>Posts</h2>
      <ul>
        {posts.map((post) => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  );
};

export default PostList;

Styling in Next.js

Styling in Next.js can be done using various approaches. You can use CSS modules, styled-jsx, or integrate popular styling libraries like Tailwind CSS or SCSS. The choice of styling method depends on your project requirements and personal preferences.