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.jsal 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
pagesfolder 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
devrun developmentbuildgenerate build ready for productionstartgenerate build and run in local env
publicstatic files, images, styles, iconsstylesglobal 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
pagesrouting system, put pages inside the pages folder. The filename is the same for the url. e.g.pages/about.js⇒http://localhost:3000/aboutpages/_app.jsWraps 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.jsPascal case for components file name.- Create as
rafceand addchildrenas 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 MyAppAs 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.csscomponents/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
Navcomponent intoLayout.jsjust before the.containerdiv 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 articleUse data fecthing method that NextJs provide to pages
getServerSidePropsfetch the data at the time of request, rather thangetStaticPropsthat fetch at build time- Can get pass in a
contextto 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 buildto generate the staticoutfolder - 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.jspages/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.