Slide 1
-----------
Part 1: Hello, everyone, and welcome to our deep dive into rendering patterns and caching! Today, we'll explore how these concepts work together to make our web applications fast and efficient, using our blog website as a running example. This is a crucial topic for any web developer, as it directly impacts user experience and website performance.
Slide 2
-----------
Part 1: Imagine you're browsing the web and stumble upon a blog with hundreds of articles. You click on a category, say "Technology," and the page loads instantly. How does the website deliver that content so quickly? The answer lies in rendering patterns and caching strategies. These techniques allow us to pre-build parts of our website and store them for later use, dramatically speeding up page load times. Without these strategies, our blog would be slow and unresponsive, leading to frustrated users and lost readership.
Part 2: These techniques allow us to pre-build parts of our website and store them for later use, dramatically speeding up page load times. In this section, we will cover rendering strategies, we will cover caching with data fetching.
Part 3: We will use a blog website as a running example.
Slide 3
-----------
Part 1: Let's start with static rendering. Think of this as pre-baking a cake. We prepare the entire cake (our webpage) ahead of time and store it. When someone wants a slice (visits the page), we simply serve it.
Part 2: Imagine our blog has a page listing all categories. This page rarely changes. We can statically render this page at build time. When a user visits /categories, they receive the pre-rendered HTML.
Slide 4
-----------
Part 1: We can also statically render individual blog posts. If a post's content is unlikely to change frequently, like an introductory post about the blog itself, we can render it at build time. The route /blog/welcome-post would be pre-built.
Slide 5
-----------
Part 1: Use static rendering for pages with content that doesn't change frequently, like about us pages, contact pages, or blog post lists.
Part 2: Avoid static rendering for pages with user-specific data or frequently changing content, like a user's profile page or a live news feed.
Slide 6
-----------
Part 1: Now, let's look at dynamic rendering. This is like ordering a custom-made pizza. We prepare the pizza (webpage) only when someone orders it (requests the page).
Part 2: In our blog example, we want to display the number of views. This number changes constantly. We need to render this page dynamically when a user requests it.
Slide 7
-----------
Part 1: Filtering blog posts by tag. When a user visits /blog?tag=react, we need to dynamically fetch and filter the posts based on the tag query parameter.
Part 2: Using useSearchParams makes this page dynamic.
Slide 8
-----------
Part 1: Use dynamic rendering for pages with user-specific data, frequently changing content, or content dependent on request parameters.
Part 2: Avoid dynamic rendering for pages with static content, as it would be unnecessarily slower than static rendering.
Slide 9
-----------
Part 1: So, how does NextJS decide when to render a route statically and when dynamically?
Part 2: Pages with no runtime data fetching, using generateStaticParams (for dynamic routes), and avoiding dynamic APIs are typically static.
Part 3: Pages with runtime data fetching, using dynamic APIs like cookies, headers, or searchParams, using cache: 'no-store', or setting dynamic = 'force-dynamic' are typically dynamic.
Slide 10
-----------
Part 1: Rendering patterns are crucial for web performance.
Part 2: Use static rendering for static content and dynamic rendering for dynamic content.
Part 3: Static content can be intelligently distributed across CDN networks for instantaneous delivery!
Part 4: NextJS intelligently handles rendering based on your code.
Part 5: Understanding these concepts is essential for building efficient web applications.
Hello, everyone, and welcome to our deep dive into rendering patterns and
caching! Today, we'll explore how these concepts work together to make our web
applications fast and efficient, using our blog website as a running example.
This is a crucial topic for any web developer, as it directly impacts user
experience and website performance.
1. INTRODUCTION
Imagine you're browsing the web and stumble upon a blog with hundreds of
articles. You click on a category, say "Technology," and the page loads
instantly. How does the website deliver that content so quickly? The answer lies
in rendering patterns and caching strategies. These techniques allow us to
pre-build parts of our website and store them for later use, dramatically
speeding up page load times. Without these strategies, our blog would be slow
and unresponsive, leading to frustrated users and lost readership.
2. OPTIMISING APPS WITH RENDERING STRATEGIES
2.1 STATIC RENDERING: PRE-BUILDING OUR BLOG
Let's start with static rendering. Think of this as pre-baking a cake. We
prepare the entire cake (our webpage) ahead of time and store it. When someone
wants a slice (visits the page), we simply serve it.
Simple Example: Imagine our blog has a page listing all categories. This page
rarely changes. We can statically render this page at build time. When a user
visits /categories, they receive the pre-rendered HTML.
Advanced Example: We can also statically render individual blog posts. If a
post's content is unlikely to change frequently, like an introductory post about
the blog itself, we can render it at build time. The route /blog/welcome-post
would be pre-built.
How it Works: During the build process, Next.js generates HTML for these routes
and stores them. When a user requests the page, the server instantly serves the
pre-rendered HTML.
When to Use: Use static rendering for pages with content that doesn't change
frequently, like about us pages, contact pages, or blog post lists.
When Not to Use: Avoid static rendering for pages with user-specific data or
frequently changing content, like a user's profile page or a live news feed.
Our Blog Example: Our /categories page is perfect for static rendering. It lists
the blog categories, which are unlikely to change often. We can also statically
render some of the blog posts themselves, particularly introductory or evergreen
content
// app/categories/page.tsx
export default function CategoriesPage() {
return (
<ul>
<li>Technology</li>
<li>Travel</li>
<li>Food</li>
</ul>
);
}
// app/blog/welcome-post/page.tsx
export default function WelcomePostPage() {
return (
<div>
<h1>Welcome to our Blog!</h1>
<p>This is an introductory post...</p>
</div>
)
}
2.2 DYNAMIC RENDERING: BUILDING ON DEMAND
Now, let's look at dynamic rendering. This is like ordering a custom-made pizza.
We prepare the pizza (webpage) only when someone orders it (requests the page).
Simple Example: Imagine a blog post page that displays the number of views. This
number changes constantly. We need to render this page dynamically when a user
requests it.
Advanced Example: Filtering blog posts by tag. When a user visits
/blog?tag=react, we need to dynamically fetch and filter the posts based on the
tag query parameter.
How it Works: Next.js renders the page on the server when a user requests it.
When to Use: Use dynamic rendering for pages with user-specific data, frequently
changing content, or content dependent on request parameters.
When Not to Use: Avoid dynamic rendering for pages with static content, as it
would be unnecessarily slower than static rendering.
Our Blog Example: Our blog post pages with view counts and the filtered blog
post pages are examples of where dynamic rendering is necessary. The content
depends on the specific post or the filter applied.
// app/blog/[slug]/page.tsx
import { notFound } from 'next/navigation';
async function getPost(slug: string) {
const res = await fetch(`https://api.example.com/posts/${slug}`);
if (!res.ok) {
throw new Error('Failed to fetch post');
}
return res.json();
}
export default async function PostPage({ params }: { params: { slug: string } }) {
const post = await getPost(params.slug);
if (!post) {
notFound();
}
return (
<div>
<h1>{post.title}</h1>
<p>Views: {post.views}</p> {/* Dynamic view count */}
<p>{post.content}</p>
</div>
);
}
// app/blog/page.tsx
import { useSearchParams } from 'next/navigation'
async function getPosts(tag?: string) {
let url = "https://api.example.com/posts"
if(tag) {
url += `?tag=${tag}`
}
const res = await fetch(url);
if (!res.ok) {
throw new Error('Failed to fetch posts');
}
return res.json();
}
export default async function BlogPage() {
const searchParams = useSearchParams()
const tag = searchParams.get('tag')
const posts = await getPosts(tag)
return (
<ul>
{posts.map(post => (
<li key={post.slug}><a href={`/blog/${post.slug}`}>{post.title}</a></li>
))}
</ul>
)
}
2.3. WHEN DOES NEXT.JS RENDER STATICALLY AND WHEN DYNAMICALLY?
It's all about how you fetch data and use certain Next.js features. Let's break
it down:
2.3.1 STATIC RENDERING:
1. No Data Fetching at Runtime: If your page doesn't need to fetch any data
after the initial page load, it's likely already statically rendered. Think
of an "About Us" page with fixed content.
2. <strong>generateStaticParams</strong> (for Dynamic Routes): If you have
dynamic routes (e.g., /blog/[slug]) and you want to pre-render specific
pages at build time, you use generateStaticParams. This function tells
Next.js which pages to generate statically. If you return all possible
paths, the site is fully statically generated. If you return some, some are
static, some are dynamic. If you return an empty array, all are dynamic.
// app/blog/[slug]/page.tsx
export async function generateStaticParams() {
return [{ slug: 'my-first-post' }, { slug: 'another-post' }]; // Static pages
}
export default function PostPage({ params }: { params: { slug: string } }) {
//...
}
3. No Dynamic APIs: Avoid using dynamic APIs like cookies, headers, or the
searchParams prop within your page if you want it to be static. These rely
on runtime information.
2.3.2. DYNAMIC RENDERING:
1. Data Fetching at Runtime: If your page needs to fetch data after the initial
page load (e.g., fetching a user's profile or displaying real-time updates),
it will be dynamically rendered.
2. Dynamic APIs: Using cookies, headers, or the searchParams prop in your page
will automatically make it dynamic. These provide information only available
at request time.
// app/blog/page.tsx
import { useSearchParams } from 'next/navigation';
export default function BlogPage() {
const searchParams = useSearchParams(); // Makes the page dynamic
const tag = searchParams.get('tag');
//...
}
3. <strong>cache: 'no-store'</strong>: Setting the cache option in a fetch call
to 'no-store' forces the data to be fetched on every request, making the
page dynamic.
fetch('/api/data', { cache: 'no-store' }); // Forces dynamic rendering
4. <strong>dynamic = 'force-dynamic'</strong>: This route segment config option
forces dynamic rendering for the entire route segment.
// app/blog/[slug]/page.tsx
export const dynamic = 'force-dynamic';
export default function PostPage() {
//...
}
In essence, if your page relies on anything that can only be known at request
time, it will be dynamic. If it can be fully determined at build time, it can be
static. Next.js intelligently handles this for you based on your code!
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