To Nha Notes | Jan. 7, 2025, 10:28 p.m.
Example:
export default async function Page() {
const data = await fetch('https://api.vercel.app/blog');
const posts = await data.json();
return (
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
Key Points:
export const dynamic = 'force-dynamic';
Example:
import { db, posts } from '@/lib/db';
export default async function Page() {
const allPosts = await db.select().from(posts);
return (
<ul>
{allPosts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
Key Points:
Client-side fetching is less common but useful in scenarios requiring dynamic updates after the page loads.
Example with useEffect:
'use client';
import { useState, useEffect } from 'react';
export function Posts() {
const [posts, setPosts] = useState(null);
useEffect(() => {
async function fetchPosts() {
const res = await fetch('https://api.vercel.app/blog');
const data = await res.json();
setPosts(data);
}
fetchPosts();
}, []);
if (!posts) return <div>Loading...</div>;
return (
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
Recommended Tools:
You can cache server-side responses to improve performance and enable ISR.
Example:
import { unstable_cache } from 'next/cache';
import { db, posts } from '@/lib/db';
const getPosts = unstable_cache(
async () => await db.select().from(posts),
['posts'],
{ revalidate: 3600, tags: ['posts'] }
);
export default async function Page() {
const allPosts = await getPosts();
return (
<ul>
{allPosts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
Key Points:
Next.js APIs like generateMetadata and generateStaticParams allow you to reuse fetched data.
The pages directory uses getServerSideProps and getStaticProps to fetch data for pages. Inside the app directory, these previous data fetching functions are replaced with a simpler API built on top of fetch() and async React Server Components.
export default async function Page() {
// This request should be cached until manually invalidated.
// Similar to `getStaticProps`.
// `force-cache` is the default and can be omitted.
const staticData = await fetch(`https://...`, { cache: 'force-cache' })
// This request should be refetched on every request.
// Similar to `getServerSideProps`.
const dynamicData = await fetch(`https://...`, { cache: 'no-store' })
// This request should be cached with a lifetime of 10 seconds.
// Similar to `getStaticProps` with the `revalidate` option.
const revalidatedData = await fetch(`https://...`, {
next: { revalidate: 10 },
})
return <div>...</div>
}
In the app directory, data fetching with fetch() will default to cache: 'force-cache', which will cache the request data until manually invalidated. This is similar to getStaticProps in the pages directory.
// `app` directory
// This function can be named anything
async function getProjects() {
const res = await fetch(`https://...`)
const projects = await res.json()
return projects
}
export default async function Index() {
const projects = await getProjects()
return projects.map((project) => <div>{project.name}</div>)
}
For further reading and examples:
By understanding these approaches, you can optimize your data fetching strategy in Next.js, balancing performance and flexibility.