# Passing Information to getStaticProps
While `getStaticProps` doesn't directly accept arguments in the way a regular function would, there are a couple of ways to pass information to it:
- Using Dynamic Routes (opens new window): If you're using dynamic routes, you can access route parameters in
getStaticProps
. - Using
context
object:getStaticProps
receives acontext
object which can contain additional information.
# Using Dynamic Routes
If you have a dynamic route, like pages/posts/[id].js
, you can access the id
parameter in getStaticProps
.
Consider the following tree structure:
➜ nextra-casiano-rodriguez-leon-alu0100291865 git:(guide) ✗ tree -I 'node_modules|api|advanced|auth|components|public|src|data|protected|*.mdx|*.jsx|_meta*' -P 'pages|posts|\[id\].js' --matchdirs
.
├── pages
│ ├── posts
│ │ └── [id].js
│ └── user
└── posts
├── 2024-12-08-leccion.md
└── 2024-12-09-leccion.md
2
3
4
5
6
7
8
9
Then you can access the id
parameter in getStaticProps
like this:
filename="pages/posts/[id].js"
import { promises as fs } from 'fs'
import path from 'path'
import { useRouter } from 'next/router'
//import { NotFoundPage } from 'nextra-theme-docs'
import { remark } from 'remark'
import html from 'remark-html'
import styles from '@/styles/Home.module.css'
import markdownStyles from '@/styles/Markdown.module.css'
export default function Post({ filename, contentHtml }) {
const router = useRouter()
if (router.isFallback) {
return <div>Loading...</div>
}
if (!contentHtml) {
return (<div className={styles.content}>
<h1 className={styles.title}>404. Page not found!</h1>
</div>)
}
return (
<div className={styles.container}>
<h1 className={styles.title}>{filename}</h1>
<article key={filename} className={styles.article}>
<div
className={`${styles.content} ${markdownStyles.markdown}`}
dangerouslySetInnerHTML={{ __html: contentHtml }}
/>
</article>
</div>
)
}
export async function getStaticProps({ params }) {
const { id } = params
const postsDirectory = path.join(process.cwd(), 'posts')
const filePath = path.join(postsDirectory, `${id}.md`)
try {
const postContent = await fs.readFile(filePath, 'utf8')
const processedContent = await remark()
.use(html)
.process(postContent)
const contentHtml = processedContent.toString()
return {
props: {
filename: id,
contentHtml,
},
}
} catch (error) {
// If the file is not found, return null for contentHtml
if (error.code === 'ENOENT') {
return {
props: {
filename: id,
contentHtml: null,
},
}
}
throw error
}
}
export async function getStaticPaths() {
const postsDirectory = path.join(process.cwd(), 'posts')
const filenames = await fs.readdir(postsDirectory)
const paths = filenames.map((filename) => ({
params: { id: filename.replace(/\.md$/, '') },
}))
return { paths, fallback: true }
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
In this example, getStaticProps
receives the id
from the URL parameters and uses it to read the corresponding file.
Notice how we're handling non-existent posts.
- In
getStaticPaths
, we've setfallback: true
(opens new window). This allows Next.js to generate pages for paths that weren't pre-rendered at build time . - In
getStaticProps
, if the file is not found, we returnnull
forpostContent
instead of throwing an error. - In the
Post
component, we've added checks for the fallback state and for whenpostContent
is null: - We use the
useRouter
hook to check if the page is in a fallback state.
- When a request comes in for a page that wasn't pre-rendered, Next.js starts generating the HTML and JSON for that page.
- During this generation process,
router.isFallback
istrue
. - Once the page generation is complete, Next.js serves the newly generated page, and for subsequent requests,
router.isFallback
will befalse
- Relationship of
router.isFallback
withfallback
ingetStaticPaths
:- If
fallback: false
,router.isFallback
will always befalse
because any paths not returned bygetStaticPaths
will result in a 404 page. - If
fallback: true
orfallback: 'blocking'
,router.isFallback
can betrue
for paths not pre-rendered at build time .
- If
- Remember,
router.isFallback
is only relevant for pages with dynamic routes that usegetStaticProps
andgetStaticPaths
. It's not applicable to pages usinggetServerSideProps
or client-side data fetching.
- If
postContent
isnull
(meaning the post wasn't found), we render a404. Page not found!
message.
Now, when you visit a post that doesn't exist:
- If the post hasn't been generated yet, you'll briefly see a
Loading...
message while Next.js attempts to generate the page. - If the post truly doesn't exist, you'll see a
404. Page not found!
message.
# The role of the function getStaticPaths
The function getStaticPaths
plays a crucial role in Next.js (opens new window) is used to specify which dynamic routes should be pre-rendered at build time.
Here's an explanation of its purpose and functionality:
Specifying Dynamic Routes:
getStaticPaths
is used to define which paths will be pre-rendered for pages that use dynamic routes. In the example above, it's determining which post IDs should be pre-rendered at build time.Static Generation: When you export
getStaticPaths
from a page that uses dynamic routes, Next.js will statically pre-render all the paths specified bygetStaticPaths
. This means that these pages are generated at build time, resulting in faster page loads and better SEO.Defining Paths: The function returns an object with a
paths
key, which is an array of objects. Each object in this array represents a route that should be pre-rendered . In our example, it's creating a path for each markdown file in theposts
directory.Fallback Behavior (opens new window):
getStaticPaths
also allows you to control the fallback behavior for paths that aren't pre-rendered. In our example,fallback: false
(opens new window) means that any paths not returned bygetStaticPaths
will result in a 404 page .Build-Time Execution:
getStaticPaths
runs at build time in production. It's not called during runtime in production, which is important for performance .
Here's a breakdown of what our getStaticPaths
function is doing:
export async function getStaticPaths() {
const postsDirectory = path.join(process.cwd(), 'posts')
const filenames = await fs.readdir(postsDirectory)
const paths = filenames.map((filename) => ({
params: { id: filename.replace(/\.md$/, '') },
}))
return { paths, fallback: false }
}
2
3
4
5
6
7
8
9
10
- It reads the
posts
directory. - For each file in the directory, it creates a
params
object with anid
that corresponds to the filename (without the.md
extension). - It returns these paths, telling Next.js to pre-render a page for each of these
id
s.
This function works in tandem with getStaticProps
. While getStaticPaths
defines which paths to pre-render, getStaticProps
is then called for each of these paths to fetch the data needed to render the page .
By using getStaticPaths
, you're able to create static pages for dynamic routes, combining the benefits of dynamic content with the performance and SEO advantages of static generation.
# Using the context
object
The context object passed to getStaticProps
Contains several properties (opens new window) that you can use :
params
: If you're using dynamic routes (opens new window),params
contains the route parameters.draftMode
:true
if the page is in the Draft Mode (opens new window) andfalse
otherwise. Is useful when your pages fetch data from a headless CMS (opens new window) and you’d want Next.js to render these pages at request time instead of build time and fetch the draft content instead of the published content. You’d want Next.js to bypass Static Generation only for this specific case.preview
: (Deprecated for draftMode) A boolean indicating if the page is in preview mode (opens new window).previewData
: (Deprecated for draftMode) The preview data set bysetPreviewData
.locale
: The active locale, if you're using internationalization.locales
: All supported locales, if you're using internationalization.defaultLocale
: The default locale, if you're using internationalization.
Here's an example using some of these properties:
import { promises as fs } from 'fs'
import path from 'path'
export default function ContextExample({ files }) {
return (
<div>
<h1>File Reader Example</h1>
<ul>
{files.map((file) => (
<li key={file.filename}>
<h3>{file.filename}</h3>
<pre>{file.content}</pre>
</li>
))}
</ul>
</div>
)
}
export async function getStaticProps(context) {
const { preview = false } = context
const postsDirectory = path.join(process.cwd(), 'posts')
const filenames = await fs.readdir(postsDirectory)
const files = await Promise.all(
filenames.map(async (filename) => {
const filePath = path.join(postsDirectory, filename)
const content = await fs.readFile(filePath, 'utf8')
return { filename, content: preview ? content : content.slice(0, 100) + '...' }
})
)
return {
props: {
files,
},
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
In this example, getStaticProps
uses the preview
flag from the context to determine whether to show full file contents or not.
In this example:
- The
getStaticProps
function reads the contents of each file in theposts
directory. - It creates an array of
files
, where each item is an object containing thefilename
andcontent
of the file. - If the page is not in preview mode, we truncate the content to the first 100 characters to avoid sending too much data. You can adjust this as needed.
- The
files
array is passed as a prop to theContextExample
component. - In the
ContextExample
component, we map over thefiles
array and render both the filename and the content of each file.
This approach allows you to access and display the file contents directly in your component. Remember that this data is fetched at build time, so if you need to update the content, you'll need to rebuild your Next.js application.
Also, keep in mind that reading and passing the full content of all files might not be efficient if you have a large number of files or if the files are very large. In such cases, you might want to consider:
- Implementing pagination
- Fetching file contents on-demand (e.g., when a user clicks on a file name)
- Using
getServerSideProps
instead ofgetStaticProps
if you need the latest file contents on each request
# Others
You can get information from environment variables vias process.env
or via fetch
or reading files from the file system.
# Building the site
See section Building the site.
# References
See the deployment at vercel https://nextra-casiano-rodriguez-leon-alu0100291865.vercel.app/ (opens new window)