Nextjs 15버전을 기준으로 작성되었습니다. 버전이 올라가면서 API가 변경될 수 있으니, 공식 문서를 참고하시기 바랍니다.
Promise.all()
을 활용합니다.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>
</>
);
}
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>
</>
);
}
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>
)}
</>
);
}
searchParams
에 따라 조건적으로 데이터를 패칭할 수 있습니다.useEffect
를 사용하거나 SWR 같은 훅 라이브러리를 활용할 수 있습니다.'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>
);
}
useEffect
는 컴포넌트가 마운트된 이후에 실행되므로, 사용자에게는 "로딩 중" 상태를 잠깐 보여줄 필요가 있습니다.'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>
);
}
fetch
의 커스터마이징과 캐시 무효화, 그리고 라우트 핸들러를 통한 데이터 통신 방식에 대해 이어서 다루겠습니다.