Engineering2024-05-10 · 8 min 읽기
Stop using useEffect for data fetching
A deep dive into Server Actions and why the client boundary matters.
Stop using useEffect for data fetching
React 개발자라면 useEffect로 데이터를 가져오는 패턴에 익숙할 것입니다. 하지만 Next.js App Router에서는 더 나은 방법이 있습니다.
기존 방식의 문제점
// ❌ 이 패턴은 이제 피해야 합니다
export default function Page() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('/api/data')
.then(res => res.json())
.then(data => {
setData(data);
setLoading(false);
});
}, []);
if (loading) return <Skeleton />;
return <Content data={data} />;
}
이 방식의 단점:
- 워터폴 요청: 컴포넌트가 렌더링된 후에야 데이터 요청 시작
- JavaScript 필요: SEO에 불리
- 로딩 상태 관리: 보일러플레이트 코드 증가
Server Components로 해결
// ✅ App Router의 권장 방식
export default async function Page() {
const data = await fetchData(); // 서버에서 실행
return <Content data={data} />;
}
Client Boundary 이해하기
'use client' 디렉티브는 단순히 "클라이언트에서 실행"을 의미하지 않습니다. 이는 경계선을 정의합니다.
// layout.tsx - Server Component
import ClientSidebar from './Sidebar';
export default function Layout({ children }) {
const user = await getUser(); // ✅ 서버에서 실행
return (
<div>
<ClientSidebar user={user} /> {/* Props로 전달 */}
{children}
</div>
);
}
Server Actions 활용
폼 제출이나 mutation도 Server Actions로 깔끔하게 처리할 수 있습니다.
// actions.ts
'use server';
export async function createPost(formData: FormData) {
const title = formData.get('title');
await db.posts.create({ title });
revalidatePath('/posts');
}
결론
Next.js App Router를 사용한다면, 서버 우선 사고방식으로 전환하세요. 대부분의 데이터 페칭은 서버에서 처리하고, 클라이언트는 인터랙션에만 집중하면 됩니다.