NextJS provides several important features that allow us to build full stack React applications. One of them is the ability to pre-render pages. In this post, we will learn about NextJS prerendering and data fetching using getStaticProps()
function.
If you are completely new to the world of NextJS, I will suggest you to begin with the post on getting started with NextJS.
1 – NextJS Prerendering and Data Fetching
In a typical React application, when the browser makes a request to the server, the server sends back the JavaScript bundle. The JavaScript code executes on the browser.
In case a React component depends on any external data from an API, the code for getting such data executes on the browser. In other words, we fetch the data after the component is loaded on the client side.
This approach works well for most applications. However, there are certain cases when this may not be the desirable behaviour.
One of the common problems with client-side rendering approach is with regards to SEO or Search Engine Optimization. Since the page is rendered on the client by executing the JavaScript, search engine crawlers are not able to extract the data available on a given page. Many search crawlers don’t have the ability to execute JavaScript and hence, they get incomplete information about your web page.
NextJS gets around this issue by supporting prerendering.
- When you make a request to a particular route in NextJS, the server returns the pre-rendered page. In other words, along with the static part of the data, NextJS can also fetch any backend data from a file or a DB.
- Next, it also hydrates the page with React code once the pre-render finishes. This is support further interactivity of the web page.
- Once both the steps are done, the application is interactive.
On a high-level, there are two types pre-rendering – static generation and server-side rendering. In this post, we will be covering static generation using NextJS.
2 – NextJS Static Generation
NextJS static generation involves pre-generating a page during build time itself. The necessary data required by the page is prepared on the server-side.
Basically, in static generation, NextJS prepares the pages ahead of time. The pages can be cached by the server or the CDN serving the app.
To support static generation, NextJS provides a special function getStaticProps()
. Check out the example using this function as below:
export default function Home(props) {
const { products } = props;
return (
<ul>
{products.map((product) => <li key={product.id}>{product.title}</li>)}
</ul>
)
}
export async function getStaticProps() {
return {props: {
products: [{ id: 'p1', title: 'Product 1'},
{ id: 'p2', title: 'Product 2'} ]
} };
}
As you can see, we have the Home
component code that renders a list of products. The product list is defined in the getStaticProps()
function. The function returns an object that contains the actual props
object. Within the props
object, we declare a list of dummy products.
Basically, we can add getStaticProps()
function to any page file in NextJS. It signals to NextJS that this particular component should be pre-rendered. Also, this function prepares the props.
While building the application, NextJS first calls the getStaticProps()
function. Then, it calls the actual component function. Basically, this allows it to prepare the props and make them available to the component.
Some important caveats with regards to NextJS getStaticProps()
function are as follows:
- We cannot place any client-side code in this function. In other words, this function does not have access to any browser APIs.
- We can use this function for any sort of server-side code such as accessing database or filesystem.
- The code within
getStaticProps()
is not included in thebundle.js
file. Since the code is not exposed to the client, we can also safely place sensitive information such as credentials within this function. However, there may be other issues in doing so.
You can find more details about this function in our post on NextJS getStaticProps.
3 – NextJS getStaticProps
File System Access
In the above example, we had hard-coded data for products. However, we can also access the file system in the getStaticProps()
function.
See below example:
import fs from 'fs/promises';
import path from 'path';
export default function Home(props) {
const { products } = props;
return (
<ul>
{products.map((product) => <li key={product.id}>{product.title}</li>)}
</ul>
)
}
export async function getStaticProps() {
console.log('Regenerating...')
const filePath = path.join(process.cwd(), 'data', 'dummy-backend.json');
const jsonData = await fs.readFile(filePath);
const data = JSON.parse(jsonData);
return {
props: {
products: data.products
}
};
}
Basically, in this case, we import two NodeJS core module fs
and path
.
While we cannot work with these modules in a typical client-side JavaScript application, we can use these modules in the getStaticProps()
function. This is because getStaticProps()
function only executes on the server-side. Also, while building the application, NextJS makes sure to strip out these server-related imports from the final bundle.js
sent to the client.
In the above example, we extract the data from a file dummy-backend.json
and use that within the props
object. See below the dummy data file.
{
"products": [
{ "id": "p1", "title": "Product 1"},
{ "id": "p2", "title": "Product 2"},
{ "id": "p3", "title": "Product 3"}
]
}
Note that the process.cwd()
function points to the root project directory.
We can now build the application using npm run build
command. This will perform the static generation of the relevant pages during the build process itself.
4 – NextJS Incremental Static Generation
In the above example, we are definitely performing NextJS prerendering of pages by fetching the product list from an external source. However, in many use-cases, the external data can also change. In other words, we can have products being added or removed. In such a case, we need a way to regenerate the static page.
NextJS provides an easy way to regenerate the static pages on every request and at most every X seconds.
To enable this feature, we have to simply add the revalidate
parameter to the output of getStaticProps()
function. See below example:
import fs from 'fs/promises';
import path from 'path';
export default function Home(props) {
const { products } = props;
return (
<ul>
{products.map((product) => <li key={product.id}>{product.title}</li>)}
</ul>
)
}
export async function getStaticProps() {
console.log('Regenerating...')
const filePath = path.join(process.cwd(), 'data', 'dummy-backend.json');
const jsonData = await fs.readFile(filePath);
const data = JSON.parse(jsonData);
return {
props: {
products: data.products
},
revalidate: 2
};
}
The revalidate
parameter takes the number of seconds before a re-generation should happen. In this case, we have kept the value as 2 seconds. This means that for any new request after two seconds of previous fetch, the page will be re-generated statically.
This feature provides a best of both worlds in terms of initial pre-render of pages and continuous regeneration depending on data changes.
Conclusion
With this, we have successfully looked at NextJS prerendering and data fetching using the extremely useful getStaticProps()
function. Basically, this function makes static regeneration of pages quite easy. It also supports continuous regeneration of these static pages.
Want to build a bigger NextJS application? Check out this post to build a NextJS event management application from scratch.
If you have any comments or queries about this post, please mention them in the comments section below.
0 Comments