Before getting started ๐
This post is based on Next.js 15. APIs may change in later versions, so consult the official documentation.
This part covers three fetch patterns commonly used in real services:
parallel
,
sequential
, and
conditional
requests.
We will also look at fetching data inside client components when that is necessary.
When several independent datasets need to be requested,
parallel fetching
is much more efficient.
Use JavaScript's
Promise.all() for this.
export default async function Page () {
const [ postsRes , usersRes ] = await Promise . all ([
fetch ( 'https://jsonplaceholder.typicode.com/posts' ),
fetch ( 'https://jsonplaceholder.typicode.com/users' ),
]);
const posts = await postsRes. json ();
const users = await usersRes. json ();
return (
<>
< h2 >Posts</ h2 >
< ul >
{ posts. map (( post : any ) => (
< li key ={ post.id } > { post.title } </ li >
)) }
</ ul >
< h2 >Users</ h2 >
< ul >
{ users. map (( user : any ) => (
< li key ={ user.id } > { user.name } </ li >
)) }
</ ul >
</>
);
}
Because both requests
run at the same time
, results arrive sooner than when they are processed sequentially.
When the result of one request is needed as a parameter for the next, the requests must run
sequentially
.
export default async function Page () {
const userRes = await fetch ( 'https://jsonplaceholder.typicode.com/users/1' );
const user = await userRes. json ();
const postsRes = await fetch (
`https://jsonplaceholder.typicode.com/posts?userId=${ user . id }`
);
const posts = await postsRes. json ();
return (
<>
< h2 > { user.name } ์ ๊ฒ์๊ธ</ h2 >
< ul >
{ posts. map (( post : any ) => (
< li key ={ post.id } > { post.title } </ li >
)) }
</ ul >
</>
);
}
This is useful when you first need to discover a user's ID, then request data associated with that ID.
Sometimes a
condition determines
whether data should be requested at all.
For example, fetch data only when a certain parameter exists.
export default async function Page ({ searchParams } : { searchParams : { userId ?: string } }) {
let posts = [];
if (searchParams.userId) {
const res = await fetch (
`https://jsonplaceholder.typicode.com/posts?userId=${ searchParams . userId }`
);
posts = await res. json ();
}
return (
<>
< h2 >๊ฒ์๊ธ ๋ชฉ๋ก</ h2 >
{ posts. length > 0 ? (
< ul >
{ posts. map (( post : any ) => (
< li key ={ post.id } > { post.title } </ li >
)) }
</ ul >
) : (
< p >๊ฒ์๊ธ์ด ์์ต๋๋ค.</ p >
) }
</>
);
}
As shown above, data can be fetched conditionally based on searchParams.
Data fetching in client components ๐
Some data cannot be handled by server components and must be fetched on the client.
Use React's
useEffect or a hook library such as SWR for this.
A basic useEffect example ๐
'use client' ;
import { useEffect, useState } from 'react' ;
export default function Page () {
const [ posts , setPosts ] = useState < any []>([]);
useEffect (() => {
fetch ( 'https://jsonplaceholder.typicode.com/posts' )
. then (( res ) => res. json ())
. then (setPosts);
}, []);
return (
< ul >
{ posts. map (( post ) => (
< li key ={ post.id } > { post.title } </ li >
)) }
</ ul >
);
}
Since useEffect runs after the component mounts, users need to see a brief loading state.
Client fetching with SWR ๐
SWR is a hook that makes data fetching in React more convenient.
It provides caching, refetching, and error handling by default.
'use client' ;
import useSWR from 'swr' ;
const fetcher = ( url : string ) => fetch (url). then (( res ) => res. json ());
export default function Page () {
const { data , error , isLoading } = useSWR (
'https://jsonplaceholder.typicode.com/posts' ,
fetcher
);
if (isLoading) return < p >๋ก๋ฉ ์ค์
๋๋ค...</ p >;
if (error) return < p >๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์ค๋ ๋ฐ ์คํจํ์ต๋๋ค.</ p >;
return (
< ul >
{ data. map (( post : any ) => (
< li key ={ post.id } > { post.title } </ li >
)) }
</ ul >
);
}
SWR's built-in caching and synchronization can improve the user experience.
We covered three practical
fetch patterns
โparallel, sequential, and conditionalโand approaches to client-side data fetching.
SWR is particularly useful for client components and worth learning.
The next part covers customizing
fetch, invalidating caches, and communicating through route handlers.
When should you use parallel fetching, and when is sequential fetching appropriate?
What SEO concerns should you consider when fetching data on the client?