Slide 1
-----------
Part 1: Welcome, everyone! In this section, we're diving into the world of Server and Client Components in NextJS. This is a game-changer for building fast and interactive web apps.
Slide 2
-----------
Part 1: We're building a blog page. We want it to be fast, interactive, and SEO-friendly. How do we achieve this?
Part 2: We want our blog to load quickly. Server Components help us achieve this by rendering content on the server, not waiting for all the javascript to be passed to client and rendered.
Part 3: But, we also want interactive elements, like "Like" buttons. Client Components take care of these, running in the user's browser.
Part 4: And, of course, we want our blog to be SEO-friendly to attract everyone to see our posts! Server Components help with this by rendering the initial content that search engines can easily crawl.
Slide 3
-----------
Part 1: Let's start with Server Components
Part 2: These components execute on the server, not in the user's browser. The user only receives rendered HTML and necessary javascript.
Part 3: They have direct access to databases, APIs, and other backend resources.
Part 4: This leads to faster initial page loads and improved SEO because the server sends the rendered HTML to the client.
Part 5: The downside of React components is that they cannot handle user interactions. Makes sense. How would a server know that a user clicked on a button?
Slide 4
-----------
Part 1: Here's an example of a Server Component fetching recent blog posts.
Part 2: This line fetches the recent posts data on the server. Note that the server components are asynchronous, and we can use asynchronous functions to retrieve our data. We'll cover data retrieval soon!
Part 3: This maps over the posts and renders each one as a list item.
Slide 5
-----------
Part 1: Now, let's look at Client Components.
Part 2: These components run in the user's browser.
Part 3: They're perfect for handling user interactions, like clicks and form submissions.
Part 4: They also manage state and update the UI dynamically.
Part 5: But any JavaScript package that the component is using must be bundled and sent to the client, increasing the bundle size and slowing down the startup process.
Slide 6
-----------
Part 1: Here's an example of a Server Component fetching recent blog posts.
Part 2: This line uses the useState hook to manage the liked state.
Part 3: This function handles the like button click.
Part 4: This is the like button. It calls the handleLike function when clicked and is disabled if already liked.
Slide 7
-----------
Part 1: Let's talk about how these components play together, and sometimes, don't.
Part 2: Server Components can render Client Components. Think of the Server Component as the stage, and the Client Component as an actor on that stage. The server sets the scene, and the client brings it to life with interactivity.
Part 3: However, Client Components cannot directly render Server Components. This is because Server Components are executed on the server, and the client doesn't have access to that environment. It's like trying to have a conversation with someone who's in another room – you need an intermediary.
Part 4: The way we connect these two worlds is through props. Server Components can pass data down to Client Components as props. This is how the server provides the initial information that the client then uses for interactivity.
Slide 8
-----------
Part 1: Here, the BlogPostPage is a Server Component.
Part 2: It fetches the blog post data.
Part 3: It then renders the PostContent and the LikeButton Client Component. Critically, it passes the necessary data, the post content and post id, as props to the Client Component. The Client Component then uses this data for its interactivity, like sending a "like" request to the server, but it does not fetch the initial post content itself. This illustrates the flow of data from Server to Client.
Slide 9
-----------
Part 1: Please remember that you can only send simple, serialisable data from the server to the client. You cannot send functions or class instances.
MASTERING SERVER AND CLIENT COMPONENTS IN NEXT.JS
1. INTRODUCTION OR MOTIVATION
You want the blog page to be as fast as possible, interactive, and SEO-friendly.
How do you achieve this? One crucial aspect is understanding how Next.js handles
rendering components: on the server or the client. This decision profoundly
impacts performance, user experience, and even how you write your code. Today,
we'll unravel the mysteries of server and client components and equip you with
the knowledge to make informed choices for your projects.
1.1 WHAT ARE SERVER COMPONENTS?
Server Components are React components that run on the server. They have direct
access to data sources, like databases or APIs, without needing client-side
fetching. This leads to faster initial page loads and improved SEO because the
server can render the content before sending it to the client.
Example: Let's say our blog page needs to fetch a list of recent posts. A Server
Component can do this directly:
TypeScript
// components/RecentPosts.tsx (Server Component)
import { getRecentPosts } from '@/lib/api'; // Hypothetical function to fetch posts
export default async function RecentPosts() {
const posts = await getRecentPosts();
return (
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
This component fetches the data on the server, renders the HTML, and sends the
complete HTML to the client. The client just displays the content—no additional
data fetching is required.
When to use: Use Server Components for data fetching, accessing backend
resources, and rendering content that doesn't require client-side interactivity.
Use also when bundling required libraries to client would unnecessarily increase
the bundles size.
When not to use: Avoid Server Components for interactive elements like buttons,
form inputs, or anything that requires immediate user feedback.
1.2 WHAT ARE CLIENT COMPONENTS?
Client Components, on the other hand, run in the user's browser. They're perfect
for handling user interactions, managing state, and updating the UI dynamically.
Example: Let's add a "Like" button to each blog post. This requires client-side
interactivity:
'use client'; // This directive makes it a Client Component, must be the first command on page
// components/LikeButton.tsx (Client Component)
import { useState } from 'react';
export default function LikeButton({ postId }: { postId: string }) {
const [liked, setLiked] = useState(false);
const handleLike = async () => {
// Logic to send like to the server
setLiked(true);
};
return (
<button onClick={handleLike} disabled={liked}>
{liked ? 'Liked!' : 'Like'}
</button>
);
}
The 'use client' directive is crucial. It tells Next.js that this component
should be rendered on the client.
When to use: Use Client Components for interactive elements, state management,
and UI updates.
When not to use: Avoid Client Components for initial data fetching or rendering
large amounts of static content, as this can lead to slower initial page loads.
1.3 COMBINING SERVER AND CLIENT COMPONENTS
The real power comes from combining these two types of components. Our blog page
can use a Server Component to fetch the initial blog post data and a Client
Component for the "Like" button.
// pages/blog/[slug].tsx
import RecentPosts from '@/components/RecentPosts';
import LikeButton from '@/components/LikeButton';
export default async function BlogPostPage({ params }: { params: { slug: string } }) {
//... fetch blog post data
return (
<div>
{/*... display blog post content */}
<LikeButton postId={/*...post id...*/} />
<RecentPosts />
</div>
)
}
> There is a limit on using client components in server components, that you can
> only pass props of simple types such as string, or number (serialisable). You
> cannot pass functions or class instances.
> ⚠️☢️⚠️ You cannot import server component into a client component
This approach gives us the best of both worlds: fast initial load from the
Server Component and rich interactivity from the Client Component.
What do you need to do?Server ComponentClient ComponentFetch data✅❌Access
backend resources (directly)✅❌Keep sensitive information on the server (access
tokens, API keys, etc)✅❌Keep large dependencies on the server / Reduce
client-side JavaScript✅❌Add interactivity and event listeners (onClick(),
onChange(), etc)❌✅Use State and Lifecycle Effects (useState(), useReducer(),
useEffect(), etc)❌✅Use browser-only APIs❌✅Use custom hooks that depend on state,
effects, or browser-only APIs❌✅Use React Class components
[https://react.dev/reference/react/Component]❌✅
https://nextjs.org/docs/app/building-your-application/rendering/composition-patterns
1.4 CONCLUSION
Today, we explored the crucial distinction between Server and Client Components
in Next.js 13. Server Components excel at data fetching and initial rendering,
improving SEO and initial load times. Client Components are essential for
interactive elements and dynamic UI updates. By strategically combining them,
you can build performant and engaging web applications. Remember to choose the
right component type for the job: Server for data, Client for interactivity!
Maggie is a generative AI that can help you understand the course content better. You can ask her questions about the lecture, and she will try to answer them. You can also see the questions asked by other students and her responses.
Join the discussion to ask questions, share your thoughts, and discuss with other learners