Next.js provides various ways to fetch data from an API or any other source. These methods can be used to either generate static pages(SSG) or for server-side rendering(SSR).
getStaticProps, getStaticPaths and getServerSideProps are used for data fetching in Next.js.
Using these techniques we can create SEO friendly websites with Next.js and pages will load much faster instead of making an API call every time and injecting content dynamically on the page which is a common limitation of a single page application or SPA.
Next.js provides different ways to fetch data which can be used to call APIs or any other data source which is used to perform different kinds of rendering as well.
Basically we use following two Next.js functions to fetch data-
getStaticProps
(For static generation):
Used to fetch data at build time.
getStaticPaths
is used as a
separate but supportive function for
getStaticProps
to help pre-render
dynamic routes.
getServerSideProps
(For server-side
rendering): Used to fetch data on every request.
getInitialProps
is also used fetch data
but it's not recommended to use in case of Next.js 9.3 or newer versions.
You can read about this more
here.
Let's talk about each one of them separately.
Let's have a basic setup so that we can explore things better.
npx create-next-app nextjs-blog
cd nextjs-blog
We will be using Axios to fetch data from an API. So install Axios
npm i axios
Then, run local development server
npm run dev
Now, open http://localhost:3000 to check if it's working.
You will see a page like this.
At this point your folder structure should look like this-
nextjs-blog/
|-- .next/
|-- node_modules
|-- pages/
| |-- api/
| |-- _app.js
| |-- index.js
|-- public/
|-- styles/
|-- .gitignore
|-- package-lock.json
|-- package.json
|-- README.md
I am showing you only pages directory because this is the place where we will be working.
So, we are going to build a basic blog to understand static page generation and server side rendering by Next JS in which we will be using api provided by https://jsonplaceholder.typicode.com/.
Open pages/index.js
and delete all the
code present in this file.
getStaticProps
Let's understand what is static page generation first.
Basically, at the build time of Next JS i.e, when we run
npm build
or
next build
command then Next JS fetches
all the data required on that page whether it is from an API or from
anywhere else and generate a simple page with all those data, very much
same as creating a HTML page by writing all the data in it directly.
And, then Next JS will serve those already created pages every time by which pages will be served much faster and no JavaScript will run to load content of page every time dynamically. This will help search engines to crawl the page with all of its content.
Basic structure of getStaticProps
export async function getStaticProps(context) {
return {
props: {}, // will be passed to the page component as props
}
}
The context
: parameter is an object
containing the following keys:
params
: contains the route parameters
for pages using dynamic routes.
preview
: is
true
if the page is in the preview mode
and undefined otherwise.
previewData
: contains the preview data
set by setPreviewData.
locale
: contains the active locale (if
enabled).
locales
: contains all supported locales
(if enabled).
defaultLocale
: contains the configured
default locale (if enabled).
getStaticProps
should return an object
with:
props
: A required object with the props
that will be received by the page component.
revalidate
: An optional amount in
seconds after which a page re-generation can occur.
notFound
: An optional boolean value to
allow the page to return a 404 status and page.
Now, add the following code into the
pages/index.js
file
// pages/index.js
import Axios from "axios";
import Link from "next/link";
const Index = (props) => {
const posts = props.data;
return (
<div>
<h1>Home</h1>
<ol>
{posts.map((post) => (
<li key={post.id}>
<Link
href={{
pathname: "/[id]",
query: { id: post.id },
}}
>
<a>{post.title}</a>
</Link>
</li>
))}
</ol>
</div>
);
};
export default Index;
export const getStaticProps = async () => {
const res = await Axios.get("https://jsonplaceholder.typicode.com/posts");
return {
props: { data: res.data.slice(0, 10) },
};
};
Here, we are creating just a simple React component but here instead of
receiving props from an parent component, we are receiving props from a
function named getStaticProps
.
Whatever we are writing inside the function
getStaticProps
will be executed at the
build time and whatever props we are returning from this function will be
received by the component.
Here, we are fetching some random posts from the API and slicing it to get just 10 posts.
Let's get some more information about
getStaticProps
Now, create a file [id].js
inside pages
folder.
If you are not getting that why we are creating file name with square
brackets [ ]
then read about dynamic
routing in NextJS
here.
Now, paste the following code in
pages/[id].js
file.
// pages/[id].js
import Axios from "axios";
import { useRouter } from "next/router";
// router is required for fallback: true
const Post = ({ post }) => {
const router = useRouter();
if (router.isFallback) {
return <div>Loading...</div>;
}
return (
<div>
<h1>Post page</h1>
<h2>{post.title}</h2>
<p>{post.body}</p>
</div>
);
};
export default Post;
export const getStaticProps = async ({ params }) => {
const { data } = await Axios.get(`https://jsonplaceholder.typicode.com/posts/${params.id}`);
const post = data;
return {
props: {
post,
},
};
};
export const getStaticPaths = async () => {
const { data } = await Axios.get("https://jsonplaceholder.typicode.com/posts");
const posts = data.slice(0, 10);
const paths = posts.map((post) => ({ params: { id: post.id.toString() } }));
return {
paths,
fallback: true,
};
};
As before, we are using getStaticProps
to
fetch data from API which will help NextJS at build time.
Now go to our home page and click any of the blogs, you will be redirected to the respective blog post.
Here, we are receiving a parameter
params
in which we will get the id of the
post to be fetched from the URL of current page.
After fetching data from API we are return it and receiving as props in
the component.
But one thing you might have noticed here we are using an extra function
getStaticPaths
here.
Try to remove this function from this file, you will get error.
getStaticPaths
First of all note that, if
getStaticProps
receives a parameter i.e.,
the page has dynamic routes then it's necessary to define
getStaticPaths
.
NextJS force us to define
getStaticPaths
function because it wants
to know what could be the other dynamic parameters are possible for which
static page has to be created in advance.
After getting all these dynamic routes, NextJS fetch them too and create static page for them.
Basic structure of getStaticPaths
export async function getStaticPaths() {
return {
paths: [
{ params: { ... } }
],
fallback: true or false
};
}
We have to return paths
in the following
format
return {
paths: [
{ params: { id: '1' } },
{ params: { id: '2' } }
],
fallback: ...
}
Now, check our code above we are returning id of 10 posts from
getStaticPaths
function in string format,
to create static page for them too.
You may notice a parameter fallback
in
the above code. Let's understand this now.
We are generating static page just for 10 posts which are having id 1 to
10.
But if you try
http://localhost:3000/100
with id 100. Even that case NextJS will show us a post but after
Loading... message.
This is happening because we have added
fallback: true
. It means that if static
page is not available after NextJS build because we have not provided this
id in getStaticPaths
function as path
then go check on the server if post with that id is available then serve
it. If a post with this id is not even available on the server then only
show Page not found
error.
If we put fallback: false
then NextJS
will check for the id on the available pages i.e., the array of id
returned by the paths
variable and if no
post is available there then it will show
Page not found
error directly without reaching to the server.
We are using useRouter
to know whether it
is a fallback request or not. This is how we can check the value of
fallback.
getServerSideProps
If a web application uses server-side rendering then it has the ability to render web page on their server instead of calling an API from the browser and injecting dynamic data. Server-side sends full page and all of its content in HTML form which will be helpful for search engines to crawl.
To achieve such functionality, NextJS provides a function
getServerSideProps
.
Basic structure of getServerSideProps
export async function getServerSideProps(context) {
return {
props: {}, // will be passed to the page component as props
}
}
The context
parameter is an object
containing the following keys:
params
: If this page uses a dynamic
route, params contains the route parameters.
req
: The HTTP IncomingMessage object.
res
: The HTTP response object.query
: The query string.preview
: preview is true if the page is
in the preview mode and false otherwise.
previewData
: The preview data set by
setPreviewData.
resolvedUrl
: A normalized version of
the request URL that strips the _next/data prefix for client transitions
and includes original query values.
The getServerSideProps
should return an
object with:
props
: A required object with the props
that will be received by the page component.
notFound
: An optional boolean value to
allow the page to return a 404 status and page.
redirect
: An optional redirect value to
allow redirecting to internal and external resources.
Now use this is on our project. Delete all the code and paste following
code in
pages/[id].js
import Axios from "axios";
const Post = ({ post }) => {
return (
<div>
<h1>Post page</h1>
<h2>{post.title}</h2>
<p>{post.body}</p>
</div>
);
};
export default Post;
export const getServerSideProps = async ({ params }) => {
const { data } = await Axios.get(`https://jsonplaceholder.typicode.com/posts/${params.id}`);
if (!data) {
return {
notFound: true,
};
}
const post = data;
return {
props: {
post,
},
};
};
As we did earlier, here we are fetching data inside
getServerSideProps
and return the data
which willl be recieved by the component. The difference is that this
function will be called everytime the page is requested and won't do
anything at the build time.
Now go to our home page and click any of the blog, you will be redirected to the respective blog post.
This is how we can use perform either static page generation or server-side rendering in our web application in NextJS as per our requirement.
AUTHOR