Notes from Next.js Crash Course from Traversy Media YouTube channel.
You should know React and be familiar with:
- Creating components
- Using Jsx
- Passing props
- Using state
You should have install:
Node.js
al least version 16.8 or later
Next is a React frontend development web framework created by Vercel that enables functionality such as SSR and SSG.
Unlike a client side framework, Next.js is optimized for SEO and performance. Also you get client side routing
- Easy page routing, create a file for a page and put it in the
pages
folder and that page will be automatically rendered. - API Routes, create API routes within the next file structure. You can use other backends.
- TypeScript and Sass, out of the box.
- SSG, export static website
- Easy deployment, developed and hosted in Vercel or any node.js hosting
Version 13
npx create-next-app@latest
Version 12
npx create-next-app@12 app-name && cd app-name && npm i next@12
dev
run developmentbuild
generate build ready for productionstart
generate build and run in local env
public
static files, images, styles, iconsstyles
global styles and specific css file for pages and components, e.g.Page.module.css
- Can’t import global styles in pages or components
import styles from '../styles/Home.module.css
pages
routing system, put pages inside the pages folder. The filename is the same for the url. e.g.pages/about.js
⇒http://localhost:3000/about
pages/_app.js
Wraps around all of your page components. You can add a layout, show a header, footer, etc.- Lowercase for pages file name.
To display a layout around, create a new layout file and import in pages/_app.js
components/Layout.js
Pascal case for components file name.- Create as
rafce
and addchildren
as a prop
- Create as
// components/Layout.js
import styles from '../styles/Layout.module.css'
const Layout = ({ children }) => {
return (
<div className={styles.container}>
<main className={styles.main}>{children}</main>
</div>
)
}
export default Layout
// pages/_app.js
import Layout from '../components/Layout'
import '../styles/globals.css'
function MyApp({ Component, pageProps }) {
return (
<Layout>
<Component {...pageProps} />
</Layout>
)
}
export default MyApp
As the same in React, all components should have a single parent element.
import Head from 'next/head'
The component to add title and meta tags, the same way as in an HTML file.
styles/Nav.module.css
components/Nav.js
- In the component
import Link from 'next/link'
for anchor tags, add links for Home and About
import Link from 'next/link'
import styles from '../styles/Nav.module.css'
const Nav = () => {
return (
<nav className={styles.nav}>
<ul>
<li>
<Link href='/'>Home</Link>
</li>
<li>
<Link href='/about'>About</Link>
</li>
</ul>
</nav>
)
}
export default Nav
- Import
Nav
component intoLayout.js
just before the.container
div tag.
Augment body
and html
tags.
Resource:
getStaticProps
, allow to fetch at build timegetServerSideProps
, allow to fetch on every request (slow)getStaticPaths
, dynamic generate paths based on the data we’re fetching
Can be used at the top or bottom of the file.
export const getStaticProps = async () => {
const res = await fetch(`https://jsonplaceholder.typicode.com/posts?_limit=6`)
const articles = await res.json()
// return props object
return {
props: {
articles,
},
}
}
Return a props object and the data we want to pass.
- Create files and folders structure
pages/article/[id]/index.js
// index.js, base code to fix 404 page
const article = () => {
return <p>This is an article</p>
}
export default article
Use data fecthing method that NextJs provide to pages
getServerSideProps
fetch the data at the time of request, rather thangetStaticProps
that fetch at build time- Can get pass in a
context
to get the id of the urlcontext.params.id
- Return an object with props
export const getServerSideProps = async (context) => {
const res = await fetch(
`https://jsonplaceholder.typicode.com/posts/${context.params.id}`
)
const article = await res.json()
return {
props: {
article,
},
}
}
Dynamic generate the path with the data
export const getStaticProps = async (context) => {
const res = await fetch(
`https://jsonplaceholder.typicode.com/posts/${context.params.id}`
)
const article = await res.json()
return {
props: {
article,
},
}
}
// Get all posts
export const getStaticPaths = async () => {
const res = await fetch('https://jsonplaceholder.typicode.com/posts/')
const articles = await res.json()
// generate paths structure
const ids = articles.map((article) => article.id)
const paths = ids.map((id) => ({ params: { id: id.toString() } }))
return {
// paths: {params: {id: '1', id: '2'}}
paths,
fallback: false,
}
}
Edit package.json
and edit build
script to add next export
"scripts": {
"build": "next build && next export",
- Run
npm run build
to generate the staticout
folder - Run
serve -s out -p 8000
- Requirement
npm i -g serve
- Requirement
Create API routes, a function that take a request and a response.
Respond with a specific status code and respond with a specific data.
Similar to Express, any backend REST API.
Create a new data.js
file in the root folder for the data.
Create as many files as you need based on the functions required: Get all posts, Get a single post.
pages/api/articles/index.js
pages/api/articles/[id].js
// index.js get all posts
import { articles } from '../../../data'
export default function handler(req, res) {
res.status(200).json(articles)
}
All posts are accessible from http://localhost:3000/api/articles/
// [id].js
import { articles } from '../../../data'
export default function handler({ query: { id } }, res) {
const filtered = articles.filter((article) => article.id === id)
if (filtered.length > 0) {
res.status(200).json(filtered[0])
} else {
res
.status(404)
.json({ message: `Article with the id of ${id} is not found.` })
}
}
Access a single post from http://localhost:3000/api/articles/1
root/config/index.js
const dev = process.env.NODE_ENV !== 'production'
export const server = dev ? 'http://localhost:3000' : 'https://yourwebsite.com'
And then import to pages/index.js
as server.
// pages/index.js
import { server } from '../config'
...
// fetch from local API
export const getStaticProps = async () => {
const res = await fetch(`${server}/api/articles`)
const articles = await res.json()
return {
props: {
articles,
},
}
}
Create a new Meta
component to use for all pages and update title, description where needed.