33
Increasing Next.js app performance with GetServerSideProps and Next/Image
I was developing an app using react and next.js and I had to decide on the method I will be fetching my data in so I had two options to render my data
Using Axios and fetching the data on the client
Using the prebuilt function GetServerSideProps and rendering on the server
So, I decided on doing both and testing the performance using pageSpeed insights.
First, The data I will be fetching is detailed in the interface below written in Typescript
export interface Post {
identifier: string
title: string
body?: string
slug: string
subName: string
username: string
createdAt: string
updatedAt: string
sub?: Sub
mediaLink?: string
bodyPreview?: string
url: string
voteScore?: number
commentCount?: number
userVote?: number
}
First, we will fetch data dynamically using Axios as demonstrated in the code snippet below
const [posts, setPosts] = useState<Post[]>([])
useEffect(() => {Axios.get('/posts').then((res)=>setPosts(res.data)).catch((err) => console.log(err))}, [])
Then I will render elements using the post component
{posts?.map((post)=>(<PostPreview post={post} key={post.identifier}/>))}
<img src={mediaLink}/>
The post component
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface PostPreviewProps { | |
post: Post | |
revalidate?: Function | |
key?: string | |
} | |
export default function PostPreviewClient({ | |
post: { | |
identifier, | |
slug, | |
title, | |
body, | |
subName, | |
createdAt, | |
voteScore, | |
userVote, | |
commentCount, | |
url, | |
username, | |
sub, | |
mediaLink, | |
bodyPreview, | |
}, | |
revalidate, | |
}: PostPreviewProps) { | |
const router = useRouter() | |
return ( | |
<div className="w-full lg:max-w-full lg:flex" key={identifier} id={identifier}> | |
<div className="flex-none h-48 overflow-hidden text-center bg-cover rounded-t lg:h-auto lg:w-48 lg:rounded-t-none lg:rounded-l " title="Post Image"> | |
<img src={mediaLink}/> | |
</div> | |
<div className="flex flex-col justify-between w-full p-4 leading-normal bg-white border-b border-l border-r border-gray-400 rounded-b lg:border-l-0 lg:border-t lg:border-gray-400 lg:rounded-b-none lg:rounded-r"> | |
<div className="mb-2"> | |
<Link href={`/topic/${subName}`}> | |
<p className="flex items-center text-sm text-gray-600 cursor-pointer hover:underline"> /topic/{subName}</p> | |
</Link> | |
<Link href={url}> | |
<div className="mb-2 text-xl font-bold text-gray-900 cursor-pointer">{title}</div> | |
</Link> | |
<p className="text-base text-gray-700">{bodyPreview}</p> | |
</div> | |
<div className="flex items-center"> | |
<div className="text-sm"> | |
<p className="leading-none text-gray-900">{username}</p> | |
<p className="text-gray-600">{dayjs(createdAt).fromNow()}</p> | |
</div> | |
</div> | |
<div className="flex flex-row w-6 h-full py-2 space-x-6 text-center lg:w-12"> | |
<div | |
className="text-gray-400 cursor-pointer hover:bg-gray-300 hover:text-red-500" | |
onClick={() => vote(1)} | |
> | |
<i | |
className={classNames('fas fa-2x fa-arrow-up', { | |
'text-red-500': userVote === 1, | |
})} | |
></i> | |
</div> | |
<p className="font-bold ">{voteScore}</p> | |
<div | |
className="text-gray-400 rounded cursor-pointer hover:bg-gray-300 hover:text-blue-600" | |
onClick={() => vote(-1)} | |
> | |
<i | |
className={classNames('fas fa-2x fa-arrow-down', { | |
'text-blue-600': userVote === -1, | |
})} | |
></i> | |
</div> | |
</div> | |
</div> | |
</div> | |
) | |
} |
First, I will wrap the Axios function used on the client-side with Next.js built-in function GetServerSideProps
import { GetServerSideProps } from 'next'
export const getServerSideProps: GetServerSideProps = async (context) => {try {
const res = await Axios.get('/post')
return { props: { posts: res.data } }
} catch (err) {
return { props: { error: 'Something went wrong' }}
}}
<Image src={mediaLink} width={16} height={16} layout="responsive"/>
but what do they do exactly
GetServerSideProps Fetches data on each request and renders it on the server then sends it to the client
because Images using Next/Image are always rendered in such a way as to avoid Cumulative Layout Shift, a Core Web Vital that Google uses in web search ranking, and Automatic Image Optimization according to Next.js
So no that I have two pages one that loads data on the server and one on the client I used PageSpeed insights to test both routes.
I analyzed both https://notus-client.vercel.app/ and https://notus-client.vercel.app/serverside
and saw an increase of about 9–14 points on mobile which is the only platform we will focus on because it is the one that benefits most from server-side rendering




As the results show the server-side approach increased the score by about 15% to 20%. which proves that this approach will be better for the app moving forward.
you can run the test if you want on
source code on GitHub: https://github.com/mage1711/Notus-client
33