Server Side NextJS
Data fetching operations should be performed on the server side whenever possible. It's important to understand that a component or page (not server actions) is a server component by default unless it is explicitly marked with "use client" directive or imported within a client component. Server components offer better performance and security for data operations.
import Loader from '@/components/Loader';
import EntitiesTable from '@/components/entitiesPage/EntitiesTable';
import PageHeader from '@/components/ui/page-header';
import { getEntities } from '@/lib/actions/Entities';
import React, { Suspense } from 'react';
import { toast } from 'sonner';
const EntitiesPage = async () => {
const { data, error, message, status } = await getEntities();
if (error) {
console.error('Error getting entities => ', error);
toast.error(message);
return <div>Error getting entities = {error}</div>;
}
if (data === null || data === undefined) {
console.error('Error getting entities => ', error);
toast.error(message);
}
return (
<Suspense fallback={<Loader />}>
<div className="w-full flex flex-col gap-5">
<PageHeader
title="Content Entities"
buttonUrl={'/entities/create'}
buttonText="Create New Entity"
/>
{data === null || data === undefined || data?.length === 0 ? (
<div>No entities found = {message}</div>
) : (
<EntitiesTable data={data} />
)}
</div>
</Suspense>
);
};
export default EntitiesPage;
Important Limitations and Best Practices
-
React Hooks in Server Components: You cannot use React hooks like
useState
oruseEffect
in server components, as these are designed for user interactions. Any component that needs to handle user interactions or perform data mutations (POST, UPDATE, DELETE operations) must be a client component. -
Loading States with Suspense: When fetching data in server components, you should wrap your code in a
Suspense
component to handle loading states properly. This allows you to show a fallback UI while the data is being fetched.
<Suspense fallback={<Loader />}>/* code */</Suspense>