Next.js (Part 2)
Neil Haddley • November 6, 2021
getStaticProps, getServerSideProps, getStaticPaths and useSWR
Pre-rendering
Next.js has two forms of pre-rendering: Static Generation and Server-side Rendering. The difference is in when Next.js generates the HTML for a page.
Static Generation is a pre-rendering approach that generates the HTML pages at build time.
Server-side Rendering is a pre-rendering approach that generates the HTML on each request.
You can create a Next.js app that uses Static Generation for some pages and Server-side Rendering for others.
Static Generation (with data)
In Next.js, after exporting a page function, a developer can export a getStaticProps function.
A getStaticProps runs at build time.
getStaticProps
A getStaticProps function can be used to generate a page based on data returned by a web service call*.
* You should not fetch an API Route from getStaticProps or getStaticPaths. Instead, write your server-side code directly in getStaticProps or getStaticPaths (or call a helper function).

getStaticProps
getServerSideProps
A getServerSideProps function is used at runtime to build a page in response to a request (with or without caching).

getServerSideProps
getStaticPaths
getStaticProps and getStaticPaths can be used together to generate multiple pages.

getStaticProps and getStaticPaths being used together
next export
next export can be used to generate html pages that can be uploaded to a static web server.
$ npm run export

npm run export

out folder with generated pages

/out/articles/36
useSWR
Once the server-side rendered parts of a page have been downloaded JavaScript running on the page can fetch data and populate the remaining parts of the page (client-side).
$ npm install swr
Catch all routes
Dynamic routes can be extended to catch all paths by adding three dots (...) inside the brackets. For example:
pages/post/[...slug].js matches /post/a, but also /post/a/b, /post/a/b/c and so on.
pages/fullname/[...slug]/index.js matches /fullname/neil, but also /fullname/neil/haddley, /fullname/neil/leonard/haddley and so on.
You can use names other than slug, such as: [...param]

Client-side code

Catch all routes
pagesarticlesindex.js
TEXT
1function index({ articles }) { 2 return ( 3 <div> 4 <ul> 5 {articles.map(article => (<li key={article.id}>{article.title}</li>))} 6 </ul> 7 </div> 8 ) 9} 10 11export default index 12 13export const getStaticProps = async () => { 14 const res = await fetch('https://jsonplaceholder.typicode.com/posts?_limit=6') 15 const articles = await res.json(); 16 17 return { 18 props: { 19 articles: articles 20 } 21 } 22}
pagesarticlesidindex.js
TEXT
1function article({ article }) { 2 3 return ( 4 <div> 5 <h1>{article.title}</h1> 6 This is article {article.id} 7 <p>{article.body}</p> 8 </div> 9 ) 10} 11 12export default article 13 14export const getServerSideProps = async (context) => { 15 const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${context.params.id}`) 16 const article = await res.json() 17 return { 18 props: { 19 article: article 20 } 21 } 22}
pagesarticlesidindex.js
TEXT
1function article({ article }) { 2 3 return ( 4 <div> 5 <h1>{article.title}</h1> 6 This is article {article.id} 7 <p>{article.body}</p> 8 </div> 9 ) 10} 11 12export default article 13 14export const getStaticProps = async (context) => { 15 const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${context.params.id}`) 16 const article = await res.json() 17 18 return { 19 props: { 20 article: article 21 } 22 } 23} 24 25export const getStaticPaths = async () => { 26 const res = await fetch(`https://jsonplaceholder.typicode.com/posts`) 27 const articles = await res.json() 28 const ids = articles.map(article => (article.id)) 29 const paths = ids.map(id => ({ params: { id: id.toString() } })) 30 31 return { 32 paths, 33 fallback: false 34 } 35}
pagesarticlesidindex.js
YAML
1import {useRouter} from 'next/router' 2import useSWR from 'swr' 3 4function article() { 5 6 const router = useRouter() 7 const {id} = router.query 8 9 if (!id) return <div>waiting...</div> 10 11 const fetcher = (...args) => fetch(...args).then(res => res.json()) 12 13 const { data, error } = useSWR(`https://jsonplaceholder.typicode.com/posts/${id}`, fetcher) 14 15 if (error) return <div>failed to load</div> 16 if (!data) return <div>loading...</div> 17 18 return ( 19 <div> 20 <h1>{data.title}</h1> 21 This is article {data.id} 22 <p>{data.body}</p> 23 </div> 24 ) 25} 26 27export default article
pagesfullname...slugindex.js
TEXT
1import {useRouter} from 'next/router' 2 3function name() { 4 5 const router = useRouter() 6 const {slug} = router.query 7 8 if (!slug) return <div>waiting...</div> 9 10 return ( 11 <div> 12 <h1>{slug.join(' ')}</h1> 13 </div> 14 ) 15} 16 17export default name