1. Data Fetching Strategies
Next.js offers several methods to fetch data, each suited for different use cases:
a. Static Site Generation (SSG)
Use
getStaticProps
to fetch data at build time.Ideal for content that doesn’t change often (e.g., blog posts, product catalogs).
// pages/posts/index.js
export async function getStaticProps() {
const res = await fetch('https://api.example.com/posts');
const posts = await res.json();
return { props: { posts } };
}
export default function PostsPage({ posts }) {
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
b. Dynamic Paths with getStaticPaths
Use alongside
getStaticProps
to generate pages for dynamic routes.
// pages/posts/[id].js
export async function getStaticPaths() {
const res = await fetch('https://api.example.com/posts');
const posts = await res.json();
const paths = posts.map(post => ({ params: { id: post.id.toString() } }));
return { paths, fallback: 'blocking' };
}
export async function getStaticProps({ params }) {
const res = await fetch(`https://api.example.com/posts/${params.id}`);
const post = await res.json();
return { props: { post } };
}
c. Server-Side Rendering (SSR)
Use
getServerSideProps
to fetch data on every request.Best for highly dynamic data (e.g., user dashboards).
export async function getServerSideProps(context) {
const res = await fetch('https://api.example.com/user', { headers: { cookie: context.req.headers.cookie } });
const user = await res.json();
return { props: { user } };
}
d. Incremental Static Regeneration (ISR)
Add
revalidate
togetStaticProps
to update static pages after a given interval.Combines SSG performance with dynamic content updates.
export async function getStaticProps() {
const data = await fetchData();
return {
props: { data },
revalidate: 60, // regenerate at most once every 60 seconds
};
}
e. Client-Side Data Fetching
Use the
swr
hook for client-side fetching and caching.
import useSWR from 'swr';
function Profile() {
const { data, error } = useSWR('/api/user', fetcher);
if (error) return <div>Failed to load</div>;
if (!data) return <div>Loading...</div>;
return <div>Welcome, {data.name}!</div>;
}
2. Advanced Dynamic Routing
File-based routing in Next.js allows powerful patterns out of the box:
a. Basic Dynamic Routes
Create a file like
pages/products/[slug].js
to handle routes such as/products/hat
.
b. Catch-All Routes
Use
[...params].js
to match multiple segments:pages/docs/[...slug].js
will match/docs/a/b/c
.
c. Optional Catch-All Routes
Use
[[...params]].js
to make catch-all segments optional, matching both/blog
and/blog/a/b
.
d. Nested Routes
Organize pages into subfolders for readability:
pages/dashboard/settings/profile.js
.
3. Preview Mode
Enable Preview Mode to toggle between draft and published content in SSG pages:
// pages/api/preview.js
export default function handler(req, res) {
res.setPreviewData({});
res.redirect(req.query.redirect || '/');
}
In your page:
export async function getStaticProps({ preview }) {
const data = await fetchPosts({ draft: preview });
return { props: { data } };
}
With these techniques, you can fetch and render data in Next.js with flexibility and performance, tailoring each page to your application’s needs. In the next chapter, we’ll dive into styling and theming strategies in Next.js.