React 19 RC의 use() 훅으로 Promise 처리 개선하기
배경
프로젝트에서 데이터 페칭 로직이 복잡해지면서 useEffect와 useState 조합이 반복되는 문제가 있었다. React 19 RC가 공개되면서 use() 훅을 테스트해볼 기회가 생겼다.
기존 방식
function UserProfile({ userId }: { userId: string }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetchUser(userId)
.then(setUser)
.catch(setError)
.finally(() => setLoading(false));
}, [userId]);
if (loading) return <Spinner />;
if (error) return <Error />;
return <div>{user.name}</div>;
}
use() 훅 적용
function UserProfile({ userId, userPromise }: { userId: string; userPromise: Promise<User> }) {
const user = use(userPromise);
return <div>{user.name}</div>;
}
// 상위 컴포넌트
function App() {
const userPromise = fetchUser('123');
return (
<Suspense fallback={<Spinner />}>
<ErrorBoundary fallback={<Error />}>
<UserProfile userId="123" userPromise={userPromise} />
</ErrorBoundary>
</Suspense>
);
}
장점
- 컴포넌트 단순화: 로딩/에러 상태 관리를 Suspense와 ErrorBoundary에 위임
- 조건부 호출 가능: 일반 훅과 달리 if문 안에서도 사용 가능
- Context와의 조합: use()는 Promise뿐만 아니라 Context도 읽을 수 있음
주의사항
- Promise를 컴포넌트 내부에서 생성하면 매 렌더링마다 새로 생성되어 무한 루프 발생
- 상위에서 Promise를 생성하거나 useMemo로 메모이제이션 필요
- 아직 RC 단계이므로 프로덕션 적용은 신중하게 판단
결론
코드가 확실히 간결해지고 선언적으로 변했다. 다만 ErrorBoundary 설정이 추가로 필요하고, Promise 생명주기 관리에 익숙해지는 시간이 필요했다. 정식 릴리즈 이후 점진적으로 적용할 계획이다.