Data fetching in Next.js
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 forgetStaticProps
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.
Basic setup
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.
Static generation 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
: istrue
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.
Understand the use of 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.
Server side rendering 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.