Pre-Rendering in Next JS
What is Rendering
It is the process of converting your React Code into HTML.
There are various types of rendering
1) Client Side Rendering [ Used By ReactJS ]
In this, the Client Receives the Basic Structure of HTML Documents, and JavaScript renders all the Elements.
2) Pre Rendering
The HTML is generated on the Server side, and on the Client Side React makes the Component Interactive using the JavaScript provided by the Server.
It is of 2 Types
-
Server-Side Rendering
- In Server Side Rendering, the HTML is generated on the Server for each request, and the Rendered HTML page and JavaScript are sent to the Client.
- On the client side, React uses JavaScript to make the HTML Page Interactive.
- For Every Request, the HTML page is generated, so not recommended due to performance Reasons.
-
Static-Site Generation [ RECOMMENDED ]
- In This, the HTML page is only generated once at the build time and is reused at each request.
Hydration → Once the client gets the pre-rendered page & the JS code, React works on that page and makes it Interactive this process is called Hydration.
⭐ We can have multiple rendering methods in a single Next.js application
⭐ By default, Next JS pre-renders all the pages with no dynamic data
⭐ Once we are on a page and we are trying to get to another page, then pre-rendering doesn’t happen cuz at that React is the in charge and manipulates the DOM using JS.
How Next JS knows which code to run on the Server Side?
1) getStaticProp()
Function
- Used for the Static site generation
- *It is a Async Function ( Returns a Promise *
**export async function getStaticProps(){
// All the Code we will write here will execute on the Server side.
// Also, this Code will not visible to the Client, So we can Include the
// Credential of the Database here.
**
- It returns an object that will contains the props[]as a key ] and then that props will pass down to the respective function
export default function MyApp(props){
const {product} = props.product;
return(
<> // React Fragments
{products.map(product=><li>{product}</li>)}
</>
)
}
// This will be executed 1st
export async function getStaticProps(){
return{
props:{
product:[
"Larry","Josh","harry"
]
}
}
}
Ques - What if there is some “Dynamic Data” in the getStaticProp()
method?
Ans - To solve this problem, we have a new key called revalidate
, which tells Next JS to re-render the page after a specific time ( in milliseconds.)
export async function getStaticProp(){
const data = await axios.get('<Dynamic Changing Data>')
return{
props:{
data:data
},
revalidate:300 // time in millisecond
}
}
This is called Incremental Static Regeneration” -** It is the property of the Next JS to update the pages after we have built the site.
We can update the pages separately without updating the whole site build.
There are 2 other keys in the return object that will be used when we have some problem in fetching the Data.
1) notFound
- It is a Boolean value, It tells whether we have received the data.
- If it was true, then Next JS shows us a 404 page.
2) redirect
- It redirects the user to another route if the data can’t be fetched.
export async function getStaticProp(){
//const data = fetching data from server
if(!data){
return{
notFound: true
}
}
if(!data){
return{
redirect:{
destination:'/'
}
}
}
return {
props:{
name: "Jayant"
}
}
}
How Next JS Renders the Dynamic Paths Pages.
Suppose we have [blogId].js file inside of Blog Folder
So it has a Dynamic path, and it can have multiple Pages.
If Next JS tries to pre-render the pages, it doesn’t know how many pages it has to generate.
To solve this problem, we have the getStaticPaths()
method.
getStaticPaths()
→ It tells Next JS for how many pages it has to render.
export async function getStaticPaths(){
return{
paths:[
{params: {pid:'1'}},
{parans:{pid:'2'}},
{params:{pid:'3'}} // In path everything is of type String
],
fallback:false
}
}
// fallback is used when we have multiple pages & preloading them will take so much time, so we only preload some mostly visited pages, and others are loaded Just in time when we go to the page URL.
// for this we have set the fallback to true , It will tell the next Js that there are more pages than this also.
export async function getStaticPath(){
return{
paths:[
{params: {pid:'1'}},
],
fallback:true || 'blocking'
}
}
// we can use either of those values, blocking means only load when the data is fetched this can leads to greater loading time but we don't have to use the loading icon.
While using the Fallback, make sure that if the user enters some invalid path, then it will give some error rather than a 404 Page
*To avoid this *
- Use the
notFound
key & Inside the Page Component wait for some time to load the Data, for this use the Loading Icon.
2**getServerSideProps()
Function**
- Used for Server side rendering
- Same as
getStaticProps()
, but it will render the pages on every request and have some more functions likeres()
andreq()
- It doesn’t have the
revalidate
key.
export async function getServerSideProps(context){
const {params , req, res} = context;
console.log(req);
console.log(res);
return{
Name:"Jayant"
}
}
- Using the res function we can send the response or attach any header to it.
- Using the req function, we get access to many things like cookies, headers etc.
- Both are Useful for the Authentication Purpose
-
It doesn’t have Methods like
getStaticPaths
, cuz pre-rendering doesn’t happen.
⭐ **getServerSideProps**
& getStaticProps
can only be exported from Page components. It will not be run on components imported into a page.
Client Side Data Fetching
- There are many situations when we don’t have to use the Server-side rendering like
- When there is a lot of Data to fetch then it just slows down the server.
- User-specific Data which we don’t want that Crawler reads that
Example →
import {useEffect,useState} from 'react'
function College() {
const [isLoading,setIsLoading] = useState(true);
const [Data,setData] = useState([]);
useEffect(()=>{
const url = 'https://next-js-ab208-default-rtdb.firebaseio.com/sales.json' //.json is firebase specific
fetch(url)
.then(res=>res.json())
.then(data=>{
console.log(data);
const loadedData = [];
for (const key in data){
loadedData.push({
id:key,name:data[key].username,age:data[key].age
})
}
setData(loadedData);
setIsLoading(false);
})
},[])
if(isLoading){
return <p>Loading...</p>
}
return (
<div>
{Data.map((item)=>{
return <p key={item.id}>{item.name} is {item.age} years old</p>
})}
</div>
)
}
export default College;
Imp → This Page is also pre-rendered cuz by default next js pre-renders all the pages, but as we are fetching the data on the client-side, that data will not be pre-rendered.
If we try to see the Source Code of this, we can only see, the Loading Paragraph
Loading....
Now for the Client-side Data Fetching we can use this as it is or we can create our own hook or we can use Someone’s other hook[SWR].
It is a React Hook for Data Fetching , you can use this if you want.
Combining Pre-fetching with Client-Side Rendering
To do this we use the getStaticProps or getServerSideProps to get the Data and then uses states to save them & then we can use the Client side rendering to update the state