Build your web apps using Next.js
Using modern technologies, the world is finding ways to stretch and enable new possibilities in online experiences. Users require experiences which are faster and easier in the case of online services.
React is a JavaScript library created by Meta for building user interfaces. It has become one of the most popular frontend libraries today. However, it requires some additional packages to work on full potential. To overcome this issue, Vercel created Next.js which is built on top of React framework which enables the building of production ready application. It supports authentication, routing, bundle optimization etc. without any configuration or third-party packages.
Getting Started
Table of contents
What is Next.js
Evolution of Next.js
Features of Next.js
Next.js vs React.js
Create your first Next.js app
Next.js 13 updates
Handson with Next.js 13
What is Next.js
React is a JavaScript library that is used for building web applications on the client's browser. It has gained popularity as the most used library among developers. However, developers faced several difficulties with the client-side rendering strategy of react such as lack of authentication, security issues, extended page loading time etc. On the other hand, Next.js eludes these problems by allowing the website to be rendered on the server-side before being sent to the client.
Next.js is an open-source web development framework built on React's UI library created by Vercel. It is lightweight, server-rendered and flexible framework that includes several additional features such as server-side rendering and generation static websites.
Nowadays, most of the developers are moving towards Next.js to build static, fully interactive, superfast and SEO friendly sites and apps that are fast and easy to use. Next.js supports styling with CSS as well as precompiled Scss and Sass, CSS-in-JS and styled JSX. The main feature of Next.js includes its capability of server-side rendering to reduce the burden on web browsers which can be applied to any part of the application or the entire project.
Evolution of Next.js
Next.js was launched in 2016 and it only provided service-side rendered at that time. Later it started supporting both frontend and backend development using React and Javascript. It enables developers to create full-stack applications using a single language which avoids the complexity of developing applications using different languages and frameworks. Later, it started providing automatic routing, data fetching, and built-in SSR methods. It also supports multiple rendering methods.
Rendering Methods in NextJS
Next.js supports three types of rendering:
1. Service Side Rendering (SSR)
For each request, the content is generated on the server and then it's sent to the browser. When user requests a page, Next.js calls a serverless function for returning backend data that is necessary to render the page. The data fetching is done in the getServerSideProps() method.
2. Pre-rendering (SSG)
It is also known as Static Site Generation (SSG), where the page is rendered before the application is deployed during the initial build. This feature was added in next.js3 as a part of the CI/CD build process. Later, Next.js was updated with Js6 and the routes were automated for both SSG and SSR. In Next.js 9, automatic static optimization was introduced that determines if the page can be rendered as static. This unique feature was adopted by Nuxt and Gatsby.
3. Deferred Rendering (ISR)
It is also known as Incremental Static Regeneration (ISR) where the page is rendered when requested by the user. It was introduced to reduce the long build time. So, subsequent users will see the page either when the optional cache time expires or when a new build occurs. If the content is user-generated or generated on request, then ISR and SSR work best.
Features of Next.js
Server Side Rendering (SSR)
When the user requests a page, the content is generated on the server side and sent to the browser. The user can read the contents of the page without waiting for the contents to load, which makes faster page loading. It also provides indexable and crawlable website, which is essential for Search Engine Optimization (SEO).
Image credits Next.js tutorial with examples (educative.io)
Data Fetching
Next.js provides two kinds of pre-rendering services. SSR enables data fetching and rendering when requested. Static generation uses the data that is already available before the request is made or during build time. It is useful where data can be pre-rendered for SEO or is publicly cached.
Automatic code splitting
Instead of creating a single JavaScript consisting of all application codes, Next.js uses libraries and JavaScript to breaks it down codes into smaller parts and serves it as and when required. This makes page loading faster, as the browser doesn't have to download Javascript and CSS.
Hot Module Replacement (HMR)
Hot module Replacement (HMR) allows developers to see any changes they have made as live in the application during development. Unlike traditional "live reload" methods, it only reloads the modules that were modified. It preserves the state of the application which significantly reduces the amount of time required to see the changes in action.
Persistent Caching for Page Bundles
Next.js supports persistent caches for pages that are not changed. It allows users to load the pages quickly in their browsers as it stores the static contents in persistent caches.
Routing
Routing is one of the core features of Next.js. Next.js uses the file-based routing system and every folder and file created inside the pages folder is automatically converted to route in Next.js. Next.js routing system is mainly divided into three - Index routing, nested routes, dynamic routes.
Index Routing
The index.js is automatically mapped as the deafult route (/
) for the homepage. For instance, you can define pages/contact/index.js
, which will automatically be mapped to the /contact
page. For the above page structure, next.js creates the URL structure as /
for the pages/index.js
, /contact/
for the pages/contact/index.js
, and /contact/details
for pages/contact/details.js
respectively.
Nested Routes
Nested routes are created within a parent route. To create a nested route, create a parent route/folder
within the pages folder and add folders or files to it. For the above page structure, the details.js
and index.js
files are nested with the contact parent route.
Dynamic Routes
To create a dynamic route, add a square bracket [id].js around the filename or the directory name. The script above makes the [detials].js
dynamic, which means the user page must be accessed with /user/arun/contact
or /user/vishnu/contact
.
Absolute Imports
Absolute imports resolve the issue of long import components statements with relatively long directories. Users don't need to import components as below,
import InputField from "../../../../../components/contact/forms/inputfield"
Instead, they can import components as below,
import InputField from "components/contact/forms/inputfield";
Linking Pages
Next.js provides the next/link for navigating between pages. For instance, the project structure is as below,
You can implement page navigation as below,
import Link from "next/link";
export default function Users({users}) {
return (
<div>
<Link href="/">Home</Link>
<Link href="/about">About</Link>
<Link href="/contact">Contact</Link>
<Link href="/users">Users</Link>
<Link href="/users/admin">Admin</Link>
</div>
)
}
Next.js vs React.js
React and Next.js are the most popular JavaScript libraries used to build user interfaces (UI). This section, we will be focused on the comparison between React.js and Next.js.
Pages and navigation
In React, react-router is used to provide page navigation by providing routes for each component. The react-router-dom library is installed and imported for each component for implementing routing in react. Next.js provides a file-based router by default to implement routing.
Server-side rendering vs Client-side rending
React uses Client-side rendering where the entire app is rendered on the screen by the browser. In React, only a basic HTML file with JavaScript is rendered and everything else is rendered by the browser.
Next.js uses Server-side rendering where the HTML file is prepared by the server and then sent to the client-side to be displayed on the UI.
As a result, the initial page loading in Next.js is much faster than React. Moreover, Next.js apps are more efficient for SEO because of Server-side rendering.
Data fetching
Next.js provides two types of pre-rendering - static generation and server-side rendering. Next.js uses getStaticProps
, getServerSideProps
function for pre-rendering. When the page is loaded on the client end, these functions are executed first and the code inside getStaticProps and getServerSideProps is not visible to the client.
In a React app with redux, actions are dispatched from the components by using the useEffect hook, reducers then update the state in the store. The useSelector hook is used to fetch the state of the component.
In a Next.js app, the getStaticProps method is used to call the APIs and once the data is fetched, it is sent to the component via props. If the data is continuously changing, the getServerSideProps function is used.
Next.js Image optimization
The <img>
tag is used for displaying images in web pages. However, Next.js provides a new API, next/image for image optimization. It offers better performance, asset flexibility, faster page loading, and visual stability.
Create your first Next.js app
In this section, we will create a Next.js application. Creating a new Next.js project is an easy task with the help of create-next-app CLI.
Prerequisites
To create a Next.js application, ensure you have nodejs and npx or npm or yarn installed on your machine.
node.js v14 or higher [download]
npm v6 or higher
Create a sample app
Create a project folder and open the terminal on that folder. Execute the following command in the terminal to create a next.js app.
npx create-next-app
create-next-app
is a package like create-react-app, but for Next.js projects. It gives us a Next project with all its dependencies installed with addition to some dummy pages and styles.
Run the app
Execute the following commands to run the app.
cd <project-name>
npm run dev
The Next.js app "development server" will start on port 3000 and you should see a page as below when you access localhost:3000. This is the starter template page which provides some helpful information about Next.js.
Project Structure
After creating a new Next.js project from a CLI, you'll notice the default folder structure of the project. It contains specific folders such as pages, public, and styles. The default folder structure for a new Next.js project is as given below.
Next.js 13 updates
App directory
Routing
Routing within the app directory is controlled by the folders inside it. The UI for a route is defined with a page.jsx file inside that folder. For instance, folder structure app/user/settings/page.jsx will render /user/settings route. There are a few optional files that can be automatically wrapped with the react pages such as loading.jsx, error.jsx, layout.jsx, template.jsx.
loading.jsx
file - An optional file that is displayed immediately when a component is first loaded or when navigating between the sibling routes. It can be created within any directory inside the app folder.error.jsx
file - An optional file that isolates the error to the smallest possible subsection of the app. The component will be replaced with it's contents whenever any error occurs inside the folder where this file is placed.layout.jsx
file - Used to define a UI that is shared across multiple places. A layout can render another layout or a page inside it.template.jsx
file - Similar to the layout.jsx file, a new instance of the component is mounted during navigation, but the state is not preserved. Layouts and templates allow us to take advantage of a concept known as partial rendering.
Mandatory root layout
There must be a file that defines the root layout at the top level of the app directory. This layout is applicable to all the routes in the app and it must define the and the <body>
tags.
Head tag
A head.jsx
file defines the contents of the <head>
tag for that folder. It can only return certain limited tags like <title>
, <meta>
, <link>
, and <script>
.
Route groups
Every folder inside the app directory contributes to the URL path. All the files and folders inside of this folder are said to be a part of that route group.
Server components
By default, all of the components created inside of the app directory are React server components. However, we can include client side codes using the use client directive in the file.
Handson with Next.js 13
Let's experiment with some of the latest features of Next.js 13. We will be working on the sample project that we have created in the previous sections for this handson. The page and layout file
Open the layout.jsx file and comment out the global.css file import.
Open the page.jsx file and replace the return statement as follows.
return <h1>Hello, Next.js!</h1>;
- Run the server to see the output.
npm run dev
- Check how the layout file impacts the overall UI. Create a
layout.module.css
file in the same directory and add the following code to it.
.header {
width: 96%;
padding: 2%;
background-color: blue;
color: white;
text-align: center;
font-size: 1.5rem;
}
- Import the styles in the
layout.jsx
file and add it to a div inside the body tag.
// import './globals.css'
import styles from './layout.module.css'
export default function RootLayout({ children }) {
return (
<html lang="en">
{/*
<head /> will contain the components returned by the nearest parent
head.jsx. Find out more at https://beta.nextjs.org/docs/api-reference/file-conventions/head
*/}
<head />
<body>
<div className={styles.header}>My First Next App</div>
{children}
</body>
</html>
)
}
The output will be as below,
Add a new folder in the app directory called info. Create a file named page.jsx inside it and add the following code to it.
export default function Page() {
return (
<div>
<h3>This is a handson on next.js 13 features.</h3>
<hr />
<h4>
Next.js 13.1 includes improvements to both the pages/ (stable) and app/
(beta) directories:
</h4>
<ul>
<li>
app Directory (Beta) Improvements: Improved reliability and
performance.
</li>
<li>
Built-in Module Transpilation: Bringing next-transpile-modules
capabilities into core.
</li>
<li>Edge Runtime (Stable): A light Node.js runtime for the Edge.</li>
<li>
Turbopack Updates: Support for Tailwind CSS, next/image, @next/font,
and more.
</li>
<li>
Middleware Improvements: Return responses and set request headers.
</li>
<li>
SWC Import Resolution: For smaller JavaScript bundles when using
barrel files.
</li>
<li>Memory usage improvements, new templates, and more!</li>
</ul>
<p>
For more: <a href="https://nextjs.org/blog/next-13-1">Next.js 13.1</a>
</p>
</div>
);
}
Navigate to the info route localhost:3000/info to see the output.
Testing the loading file
Let's create loading.jsx file inside the info folder using the following code.
export default function Loading() {
return <h1>Loading...</h1>
}
Add a navigation link inside the info/pages.jsx file to navigate to the default (/) route.
<p>return to <Link href="/">main page</Link></p>
The loading UI will appear for a second when user clicks on the main page link.
Testing the error file
Create an error.jsx file in the info folder and add the following code to it. This file will act as an error boundary in case any error occurs either inside this component or to any of its components in its subtree.
'use client';
import { useEffect } from 'react';
export default function Error({
error,
reset,
}) {
useEffect(() => {
// Log the error to an error reporting service
console.error(error);
}, [error]);
return (
<div>
<div>ERROR</div>
<p>Something went wrong!</p>
<button onClick={() => reset()}>Reset error boundary</button>
</div>
);
}
Two props are passed to this component: the error prop provides more details about the error, and the reset function resets the error boundary.
Data fetching
Let's try to fetch random jokes from the Jokes API in the app. Create a new folder called jokes within the app folder. Create a file called pages.jsx and add the following code to it.
async function getData() {
const res = await fetch(
"https://v2.jokeapi.dev/joke/Programming?type=single&amount=10"
);
return res.json();
}
export default async function Page() {
const data = await getData();
return (
<div>
<h2>Tell me a joke</h2>
<hr />
<ul>
{data &&
data?.jokes?.map((item, index) => {
return <li>{item?.joke}</li>;
})}
</ul>
{data.joke}
</div>
);
}
Navigate to the jokes route localhost:3000/jokes to see the output.
_________________________________________________________________________________________
This blog was submitted for the 'Development' track for the Hashnode and WeMakeDevs July blogging challenge. Thanks to them for the opportunity. If you enjoyed this explanation of Building your Web app using Next.js, do check out my other articles as well. Thanks for reading! ❤️