use()를 쓰면 컴포넌트가 프로미스를 동기 값처럼 읽을 수 있고, 기다림은 Suspense가 맡아. 대신 렌더링 사이에 같은 프로미스를 유지해야 해.
기본 모양
function MyComp({ promise }: { promise: Promise<T> }) {
const data = use(promise);
return <p>{data.value}</p>;
}
프로미스가 대기 중이면 use()가 렌더링을 중단하고 React는 가장 가까운 Suspense의 대체 UI를 보여 줘. 프로미스가 거부되면 use()가 오류를 던지고 가장 가까운 오류 경계가 처리해. 이행된 뒤에는 값을 반환하므로 컴포넌트 본문에는 성공 경로만 남아.
핵심 규칙: 렌더링 사이에 같은 프로미스를 유지해
use()는 프로미스를 참조 동일성으로 구분해. 컴포넌트 안에서 렌더링할 때마다 새 프로미스를 만들면 React는 매번 새로운 대기 작업으로 판단하고 다시 중단해. 그러면 로딩 화면이 끝나지 않을 수 있어.
프로미스는 컴포넌트 밖에서 만들거나, 부모에서 만들어 prop으로 넘기거나, ref나 Context에 보관하거나, TanStack Query처럼 캐시를 관리하는 도구에서 가져와야 해.
안정적인 프로미스를 얻는 세 곳
- 부모 prop: 부모가 한 번 만들었거나 캐시에서 가져온 프로미스를 자식에게 넘기고, 자식은
use()로 읽어. - 모듈 수준 상수: 앱 시작 때 한 번만 읽는 데이터에 적합해.
- 캐시된 팩토리: 같은 인자를 받으면 같은 프로미스를 돌려주는 함수야. React의
cache헬퍼나 직접 만든 Map 기반 캐시를 사용할 수 있어.
Context와 use()
use()는 Context도 읽을 수 있어. useContext와 달리 조건부 호출이 허용되므로 if (someCondition) { const value = use(MyCtx); } 같은 코드도 합법이야. 일부 분기에서만 Context 값이 필요할 때 유용해.
use()는 비동기 책임의 위치를 바꿔. 이전에는 각 컴포넌트가 로딩 상태를 직접 들고 있었지만, use()를 쓰면 기다림은 위쪽 Suspense 경계로 올라가. 말단 컴포넌트는 값이 준비된 것처럼 단순하게 읽을 수 있고, 대신 부모나 캐시 계층이 안정적인 프로미스를 제공할 책임을 져.