https://github.com/emanuelefavero/next-js
A Next.js cheat sheet repository
https://github.com/emanuelefavero/next-js
cheatsheet javascript next nextjs react
Last synced: 6 months ago
JSON representation
A Next.js cheat sheet repository
- Host: GitHub
- URL: https://github.com/emanuelefavero/next-js
- Owner: emanuelefavero
- Created: 2023-01-19T11:31:11.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2023-01-28T01:25:53.000Z (over 2 years ago)
- Last Synced: 2025-03-29T16:13:38.707Z (6 months ago)
- Topics: cheatsheet, javascript, next, nextjs, react
- Language: JavaScript
- Homepage:
- Size: 43.9 KB
- Stars: 66
- Watchers: 3
- Forks: 16
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Next JS
A Next.js cheat sheet repository
## Example Projects
| Project | Description |
| ------------------------------------------ | --------------------------------------- |
| [next-js-example-app](next-js-example-app) | A bare-bone example app with local data |## Table of Contents
- [Create a new Next.js app](#create-a-new-nextjs-app)
- [ESLint](#eslint)
- [Manual Installation](#manual-installation)
- [Folder Structure](#folder-structure)
- [Routing](#routing)
- [Meta tags](#meta-tags)
- [The `_app.js` file](#the-_appjs-file)
- [The `Layout` component](#the-layout-component)
- [Sass](#sass)
- [Tailwind CSS](#tailwind-css)
- [Styled JSX](#styled-jsx)
- [The `_document.js` file](#the-_documentjs-file)
- [The `Image` component](#the-image-component)
- [The `Script` component](#the-script-component)
- [Fetch data](#fetch-data)
- [Example of using `getStaticPaths` and `getStaticProps` together](#example-of-using-getstaticpaths-and-getstaticprops-together)
- [Fetch Data on the client](#fetch-data-on-the-client)
- [SWR](#swr)
- [When to use **Static Generation** v.s. **Server-side Rendering**](#when-to-use-static-generation-vs-server-side-rendering)
- [Dynamic routes](#dynamic-routes)
- [Custom 404 pages](#custom-404-pages)
- [Export Static Site](#export-static-site)
- [API Routes](#api-routes)
- [Check for `development` mode or `production` mode](#check-for-development-mode-or-production-mode)
- [Custom Meta Component](#custom-meta-component)
- [useRouter Hook](#userouter-hook)
- [useRouter Redirect](#userouter-redirect)
- [Redirects](#redirects)## Create a new Next.js app
```bash
npx create-next-app
```### Use TypeScript, ESLint and npm
```bash
npx create-next-app --typeScript --eslint --use-npm
```## ESLint
Add the following to the `.eslintrc.json` file
```json
{
// "extends": ["next/core-web-vitals"]
"root": true,
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint"],
"extends": [
"plugin:@next/next/recommended",
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended"
],
"parserOptions": {
"ecmaVersion": 2020
},"env": {
"es6": true
}
}
```## Manual Installation
- Add Next.js to your project
```bash
npm install next react react-dom
```- Add the following scripts to your package.json
```json
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
}
```## Folder Structure
**Pages folder** - is the only required folder in a Next.js app. All the React components inside pages folder will automatically become routes
> Note: The name of the file will be the route name, use lowercase for the file name and PascalCase for the component name
**Public folder** - contains static assets such as images, files, etc. The files inside public folder can be accessed directly from the root of the application
**Styles folder** - contains stylesheets, here you can add global styles, CSS modules, etc
> Usually `globals.css` is imported in the `_app.js` file
**Components folder** - contains React components
### The `@` alias
The `@` alias is used to import files from the root of the project
```jsx
import Header from '@/components/Header'
```To use the `@` alias, add the following to the `jsconfig.json` file at the root of the project
```json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["*"]
}
}
}
```## Routing
- **Link** - is used for client-side routing. It is similar to the HTML `` tag
```jsx
import Link from 'next/link'export default function Home() {
return (
About
)
}
```## Meta tags
- **Head** - is used to add meta tags to the page
```jsx
import Head from 'next/head'export default function Home() {
return (
My page title
)
}
```> The `Head` component should be placed inside the `Layout` component or inside the `_app.js` file
### Give a different title to each page
- Import the `Head` component and put the `title` tag inside it
## The `_app.js` file
Wrap around each page and here is where you would import global styles and put header and footer components
> Note: You could also put the header and footer components inside the `Layout` component
## The `Layout` component
- Create a `Layout` component and wrap around each page with children prop
```jsx
import Header from '@/components/Header'
import Footer from '@/components/Footer'export default function Layout({ children }) {
return (
{children}
)
}
```- Import the `Layout` component in the `_app.js` file
```jsx
import Layout from '@/components/Layout'function MyApp({ Component, pageProps }) {
return (
)
}export default MyApp
```## Sass
Next.js has built-in support for Sass
- Install `sass`
```bash
npm i -D sass
```## Tailwind CSS
- Install `tailwindcss`
```bash
npm install -D tailwindcss autoprefixer postcss
```- Create a `tailwind.config.js` file at the root of the project
```bash
module.exports = {
content: [
'./pages/**/*.{js,ts,jsx,tsx}',
'./components/**/*.{js,ts,jsx,tsx}',
],
theme: {
extend: {},
},
plugins: [],
}
```> Note: If you are using the `src` folder, change the path to `./src/pages/**/*.{js,ts,jsx,tsx}` and `./src/components/**/*.{js,ts,jsx,tsx}`
- Create a `postcss.config.js` file at the root of the project
```bash
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
```- Add the following to `globals.css`
```css
@tailwind base;
@tailwind components;
@tailwind utilities;
```- Import `globals.css` in the `_app.js` file
```jsx
import '@/styles/globals.css'
```## Styled JSX
Styled JSX is a CSS-in-JS library that allows you to write CSS inside a React component
It has two modes: global and scoped
- **Global** - styles are applied globally to the entire application
```jsx
export default function Home() {
return (
<>
Your JSX here
{`
p {
color: red;
}
`}
>
)
}
```- **Scoped** - styles are applied only to the component
```jsx
export default function Home() {
return (
<>
Your JSX here
{`
p {
color: red;
}
`}
>
)
}
```> Note: If in vs-code the syntax highlighting for the `style` tag is not working, you can install the `vscode-styled-components` extension to fix this
>
> Be sure that the curly braces are on the same line as the `style` tag: `{`
>
> No need to use styled jsx if you use other methods like CSS modules or styled components## The `_document.js` file
Here you can customize the `html` and `body` tags
> For instance you can add a `lang` attribute to the `html` tag
```jsx
import Document, { Html, Head, Main, NextScript } from 'next/document'export default function Document() {
return (
<Html lang='en'>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
```> Note: This file will be created if you create a new Next.js app with `npx create-next-app`
## The `Image` component
You can use the `Image` component to add images
> The images will be optimized automatically
```jsx
import Image from 'next/image'export default function Home() {
return (
<div>
<Image src='/images/profile.jpg' width={144} height={144} />
</div>
)
}
```> Note: src, width and height are required, alt is recommended
- if you use a remote image, you need to add the domain to the `next.config.js` file
```bash
images: {
domains: ['images.pexels.com'],
},
```- or in Next.js 12.4.0:
```bash
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'example.com',
port: '',
pathname: '/account123/**',
},
],
},
```## The `Script` component
You can use the `Script` component to add scripts
```jsx
import Script from 'next/script'export default function Home() {
return (
<div>
<Script src='https://code.jquery.com/jquery-3.6.0.min.js' />
</div>
)
}
```> Note: you can add cdn scripts as well as local scripts in the `public` folder
## Fetch Data
Next.js let's you choose how to fetch data for each page. It is advised to use `getStaticProps` for most of the pages and `getServerSideProps` for pages with frequently updated data
- **getStaticProps** - is used to fetch data at build time
> Note: During development with `npm run dev`, `getStaticProps` runs on every request
>
> `getStaticProps` can only be exported from a page. You can't export it from non-page files```jsx
export async function getStaticProps() {
const res = await fetch('https://.../posts')
const posts = await res.json()return {
props: {
posts,
},
}
}
```> `posts` will be passed to the component as a prop:
```jsx
export default function Home({ posts }) {
return (
<div>
{posts.map((post) => (
<h3>{post.title}</h3>
))}
</div>
)
}
```- **getStaticPaths** - is used to specify dynamic routes to pre-render pages based on data
```jsx
export async function getStaticPaths() {
const res = await fetch('https://.../posts')
const posts = await res.json()const paths = posts.map((post) => ({
params: { id: post.id },
}))return { paths, fallback: false }
}
```> Note: When `fallback` is `false`, any paths not returned by `getStaticPaths` will result in a 404 page
>
> If `fallback` is `true`, then when a user visit a page that is not pre-rendered, Next.js will generate the page on the fly and return it to the user (useful for sites with frequently updated data like a social network)- **getServerSideProps** - is used to fetch data on the server on each request
```jsx
export async function getServerSideProps(context) {
return {
props: {
// props for your component
},
}
}
```> `getStaticProps` and `getServerSideProps` have a `context` parameter that contains the url `params` object
>
> You can use this to fetch data for a specific post (e.g. `context.params.id`)### Example of using `getStaticPaths` and `getStaticProps` together
Use `getStaticPaths` to fetch an array of IDs and use `getStaticProps` to fetch data for each product based on the ID
```jsx
export async function getStaticPaths() {
const res = await fetch('https://.../posts')
const posts = await res.json()const paths = posts.map((post) => ({
params: { id: post.id },
}))return { paths, fallback: false }
}export async function getStaticProps({ params }) {
const res = await fetch(`https://.../posts/${params.id}`)
const post = await res.json()return {
props: {
post,
},
}
}
```## Fetch Data on the client
> Sometimes it can be beneficial to fetch data on the client instead of on the server.
>
> For example, you could fetch all the static data on the server and then fetch the dynamic data on the client such as a user-specific data that changes frequently and is not needed for SEO.- **useEffect** - is used to fetch data on the client
```jsx
import { useEffect, useState } from 'react'export default function Home() {
const [posts, setPosts] = useState([])useEffect(() => {
fetch('https://.../posts')
.then((res) => res.json())
.then((data) => setPosts(data))
}, [])return (
<div>
{posts.map((post) => (
<h3 key={post.id}>{post.title}</h3>
))}
</div>
)
}
```## SWR
> SWR is a React Hooks library for remote data fetching on the client
>
> You should use it instead of `useEffect````jsx
import useSWR from 'swr'export default function Home() {
const { data, error } = useSWR('api/user', fetch)if (error) return <div>failed to load</div>
if (!data) return <div>loading...</div>return (
<>
{data.map((post) => (
<h3 key={post.id}>{post.title}</h3>
))}
</>
)
}
```## When to use **Static Generation** v.s. **Server-side Rendering**
Use Static Generation whenever possible because it's much faster than Server-side Rendering and the page can be served by CDN.
You should ask yourself:
- Can I pre-render this page ahead of a user's request?
If the answer is yes, then you should choose Static Generation.
- Does the page need to update frequently?
If the answer is yes, then you should choose Server-side Rendering.
You can use Static Generation for many types of pages, including:
- Marketing pages
- Blog posts
- E-commerce product listings
- Help and documentationYou could also skip Server-side Rendering and use client-side JavaScript to fetch data with `useEffect`
## Dynamic Routes
- Create a folder inside the `pages` folder with the name of the dynamic route in square brackets (e.g. `[id]`)
- Create an `index.js` file inside the dynamic route folder
### Dynamic Links
- Create a link with that points to the dynamic route and pass the dynamic value as a prop
```jsx
import Link from 'next/link'export default function Post({ post }) {
return (
<div>
<Link href='/posts/[id]' as={`/posts/${post.id}`}>
<a>{post.title}</a>
</Link>
</div>
)
}
```> Note: this is usually done inside a `map` function
### Catch All Routes
Dynamic routes can be extended to catch all paths by adding three dots (...) inside the brackets. For example:
- `pages/posts/[...id].js` matches `/posts/a`, but also `/posts/a/b`, `/posts/a/b/c` and so on.
If you do this, in getStaticPaths, you must return an array as the value of the id key like so:
```jsx
return [
{
params: {
// Statically Generates /posts/a/b/c
id: ['a', 'b', 'c'],
},
},
//...
]
```And params.id will be an array in getStaticProps:
```jsx
export async function getStaticProps({ params }) {
// params.id will be like ['a', 'b', 'c']
}
```## Custom 404 pages
- Create a `404.js` file inside the `pages` folder
```jsx
export default function Custom404() {
return <h1>404 - Page Not Found</h1>
}
```> Note: You can also create a `500.js` file for the server error page
## Export Static Site
Export a static site with `next export`
> Add an npm script to the `package.json` file:
```json
"scripts": {
"export": "next build && next export"
}
```> Run the script:
```bash
npm run export
```> The static site will be exported to the `out` folder
>
> You can deploy this folder to any static site host such as GitHub Pages#### Build a local server to test the static site
- Install `serve`
```bash
npm i -g serve
```- Run the server
```bash
serve -s out -p 8000
```## API Routes
You can work with any database in the `pages/api/` folder
> Note: Any API route that is placed inside this folder will be accessible like any other page in Next.js
- Create a folder inside the `pages` folder with the name of the API route (e.g. `api/posts`)
### Work with local data
- Create a `data.js` file at the root of the project
```js
const posts = [
{
id: 1,
title: 'Post 1',
},
{
id: 2,
title: 'Post 2',
},
{
id: 3,
title: 'Post 3',
},
]
```- Import the data in the API route
```js
import { posts } from '@/data'
```- Get the data
```js
export default function handler(req, res) {
res.status(200).json(posts)
}
```> You can now fetch the data as you would with any other API
>
> Note: Next.js needs absolute paths when fetching data## Check for `development` mode or `production` mode
Since Next.js needs absolute paths when fetching data, you can check if you are in `development` mode or `production` mode
- Create a `config.js` folder at the root of the project with an `index.js` file inside
```js
const dev = process.env.NODE_ENV !== 'production'export const server = dev ? 'http://localhost:3000' : 'https://yourwebsite.com'
```- Now you can use `server` as a variable in your code as an absolute path when fetching data
```js
import { server } from '@/config'export default function handler(req, res) {
fetch(`${server}/api/posts`)
.then((res) => res.json())
.then((data) => res.status(200).json(data))
}
```## Custom Meta Component
> Note: There is no need to create a custom meta component since we can use the `Head` component from Next.js
A meta component is used to add meta tags to the `head` of the document
- Create a `Meta.js` file inside the `components` folder
```jsx
import Head from 'next/head'export default function Meta({ title, keywords, description }) {
return (
<Head>
<meta charSet='utf-8' />
<meta name='viewport' content='width=device-width, initial-scale=1' />
<link rel='icon' href='/favicon.ico' />
<meta name='keywords' content={keywords} />
<meta name='description' content={description} />
<title>{title}</title>
</Head>
)
}
```> Tip: You can also use packages such as `next-seo` for this
- Add `defaultProps` to the `Meta` component so that you don't need to add props to it every time you use it
```jsx
Meta.defaultProps = {
title: 'WebDev News',
keywords: 'web development, programming',
description: 'Get the latest news in web dev',
}
```- Now you can use the `Meta` component in any page (it is common to use it in the `Layout` component)
```jsx
import Meta from '@/components/Meta'export default function Layout({ children }) {
return (
<div>
<Meta />
{children}
</div>
)
}
```### Add a specific title to a page
- Import the `Meta` component in the specific page and pass the title as a prop
```jsx
import Meta from '@/components/Meta'export default function About() {
return (
<div>
<Meta title='About' />
<h1>Welcome to the About Page</h1>
</div>
)
}
```##
## useRouter Hook
useRouter is a hook that gives you access to the router object
- Import the `useRouter` hook
```jsx
import { useRouter } from 'next/router'
```- Use the `useRouter` hook
```jsx
const router = useRouter()
```- Get the query
```jsx
const router = useRouter()
const { query } = router
```- Get the query with destructuring
```jsx
const {
query: { id },
} = useRouter()
```useRouter main properties:
- `pathname` - Current route. That is the path of the page in `pages`
- `route` - Current route with the query string
- `query` - Query string section of URL parsed as an object
- `asPath` - String of the actual path (including the query) shown in the browser## useRouter Redirect
- Import the `useRouter` hook
```jsx
import { useRouter } from 'next/router'
```- Use the `useRouter` hook to redirect the user to home page
```jsx
const router = useRouter()
router.push('/')
```> Note: You can for instance use this hook in a `404` page to redirect the user to the home page after 3 seconds
## Redirects
To redirect a user to another page, you can use `redirects` on `next.config.js`
```js
module.exports = {
async redirects() {
return [
{
source: '/about',
destination: '/',
permanent: false,
},
]
},
}
```> Note: `permanent: true` will tell the browser to cache the redirect forever. That means that if the user goes to the `/about` page, the browser will redirect the user to the `/` page without making a request to the server
>
> TIP: Do not use `permanent: true` for redirects that are not permanent### Redirects HTTP status codes
- `308` - Permanent Redirect
- `307` - Temporary Redirect> Note: `308` replaces `301`, `307` replaces `302`
---
[**Go To Top ⬆️**](#next-js)