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
}
Fetching data on the client
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}/>))}
The client-side post component will be using the default HTML tag
<img src={mediaLink}/>
The post component
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> | |
) | |
} |
Fetching data on the server
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' }}
}}
and in the post component, I will be using Next/Image component instead of
<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.
Test Results
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
Top comments (0)