SWR
SWR
Vercel의 데이터 fetching 라이브러리. stale-while-revalidate 전략.
SWR
Vercel의 데이터 fetching 라이브러리. stale-while-revalidate 전략.
SWR은 Vercel이 개발한 React용 데이터 페칭 라이브러리로, "stale-while-revalidate" HTTP 캐시 전략에서 이름을 따왔습니다. 먼저 캐시된 데이터를 반환하고(stale), 백그라운드에서 최신 데이터를 가져와(revalidate) 갱신합니다.
SWR의 핵심은 useSWR 훅입니다. 키(보통 API URL)와 fetcher 함수를 받아 data, error, isLoading 상태를 반환합니다. 같은 키로 여러 컴포넌트에서 호출해도 요청은 자동으로 중복 제거(deduplication)됩니다.
SWR은 포커스 시 자동 갱신, 폴링, 낙관적 업데이트, 에러 재시도 등 다양한 기능을 내장합니다. 또한 SSR과 완벽하게 호환되어 서버에서 가져온 데이터를 클라이언트로 전달할 수 있습니다.
TanStack Query(React Query)와 비교하면 SWR은 더 가볍고 단순합니다. 복잡한 캐싱 전략이나 mutation 관리가 필요하면 TanStack Query, 간단한 데이터 페칭에는 SWR이 적합합니다.
import useSWR, { useSWRConfig, mutate } from 'swr';
// 기본 fetcher 함수
const fetcher = (url: string) => fetch(url).then(res => res.json());
// 기본 사용법
function Profile() {
const { data, error, isLoading, isValidating } = useSWR(
'/api/user',
fetcher,
{
revalidateOnFocus: true,
revalidateOnReconnect: true,
refreshInterval: 30000, // 30초마다 자동 갱신
dedupingInterval: 2000, // 2초 내 중복 요청 방지
}
);
if (error) return <div>에러가 발생했습니다</div>;
if (isLoading) return <div>로딩중...</div>;
return (
<div>
<h1>{data.name}</h1>
{isValidating && <span>업데이트 중...</span>}
</div>
);
}
// 조건부 페칭
function UserPosts({ userId }: { userId?: string }) {
// userId가 없으면 요청 안 함
const { data } = useSWR(
userId ? `/api/users/${userId}/posts` : null,
fetcher
);
return <PostList posts={data} />;
}
// 낙관적 업데이트 (Optimistic Update)
function TodoItem({ todo }: { todo: Todo }) {
const handleToggle = async () => {
// 즉시 UI 업데이트
mutate(
'/api/todos',
(todos: Todo[]) =>
todos.map(t => t.id === todo.id ? { ...t, done: !t.done } : t),
{ revalidate: false }
);
// 서버에 요청
await fetch(`/api/todos/${todo.id}`, {
method: 'PATCH',
body: JSON.stringify({ done: !todo.done })
});
// 서버 데이터로 재검증
mutate('/api/todos');
};
return <div onClick={handleToggle}>{todo.title}</div>;
}
// useSWRMutation으로 mutation 처리
import useSWRMutation from 'swr/mutation';
async function createPost(url: string, { arg }: { arg: { title: string } }) {
return fetch(url, {
method: 'POST',
body: JSON.stringify(arg)
}).then(r => r.json());
}
function NewPost() {
const { trigger, isMutating } = useSWRMutation('/api/posts', createPost);
const handleSubmit = async (title: string) => {
await trigger({ title });
mutate('/api/posts'); // 목록 갱신
};
return <button disabled={isMutating}>{isMutating ? '저장중...' : '작성'}</button>;
}
기술 미팅에서:
"대시보드에서 같은 API를 5군데서 호출하고 있어요. SWR 쓰면 자동으로 중복 제거되고, 포커스할 때 최신 데이터로 갱신됩니다. 실시간 느낌도 나고요."
기술 면접에서:
"stale-while-revalidate 전략이 뭔가요?" - "캐시된 오래된 데이터를 먼저 보여주고, 백그라운드에서 최신 데이터를 가져와 갱신합니다. 사용자는 즉시 콘텐츠를 보고, 곧 최신 상태로 업데이트됩니다."
코드 리뷰에서:
"좋아요 누를 때 서버 응답 기다리면 느려요. mutate로 낙관적 업데이트 먼저 하고, 실패하면 롤백하는 패턴 쓰세요. 체감 속도가 완전 달라집니다."