isLoading
과 같은 state를 이용해서 로딩 중임을 나타내고 isLoading
이 true일 때 로딩 컴포넌트를 보여주는 식으로 UI를 구성함.Promise.all
로 병렬적으로 fetch 해오면 부모 컴포넌트의 fetch가 끝날 때까지 기다리지 않고 자식 컴포넌트가 필요한 데이터 fetch를 시작할 수 있음. → waterfall 문제는 해결됨.// 이 함수는 Promise가 아니라 Suspense의 특별한 객체입니다.
const resource = fetchProfileData();
function ProfilePage() {
return (
<Suspense fallback={<h1>Loading profile...</h1>}>
<ProfileDetails />
<Suspense fallback={<h1>Loading posts...</h1>}>
<ProfileTimeline />
</Suspense>
</Suspense>
);
}
function ProfileDetails() {
// Try to read user info, although it might not have loaded yet
const user = resource.user.read(); //데이터를 읽는 메소드
return <h1>{user.name}</h1>;
}
function ProfileTimeline() {
// Try to read posts, although they might not have loaded yet
const posts = resource.posts.read();
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.text}</li>
))}
</ul>
);
}
위 예시에서, ProfilePage
는 ProfileDetails
와 ProfileTimeline
을 자식 컴포넌트로 가짐. 각각의 자식 컴포넌트는 resource
함수를 이용해 데이터를 읽으려고 함.
read()
메소드는 데이터 fetch를 시작하는 메소드가 아님! 이미 가져온 데이터를 읽으려고 함.
최상단에서 fetchProfileData()
를 호출한 순간 이미 fetch는 시작됨.
위 예시에서 렌더링이 일어나는 과정
fetchProfileData()
를 호출하면서 이미 데이터 fetch가 시작됨. 이 함수는 Promise를 반환하는 대신 특별한 resourse를 반환함.ProfilePage
를 렌더링하려고 함. 여기에는 두 개의 자식 컴포넌트가 있음.ProfileDetails
가 렌더링되려고 함. 이 컴포넌트는 resource.user.read()
를 호출함. 아직 데이터 fetch가 끝나지 않았기 때문에, 이 컴포넌트는 **suspend(대기)**됨. 리액트는 이 컴포넌트를 건너뛰고, 컴포넌트 트리에서 다른 렌더링할 컴포넌트가 없는지 탐색함.ProfileTimeline
가 렌더링되려고 함. 이 컴포넌트는 resource.posts.read()
를 호출함. 이 컴포넌트 역시 아직 데이터 fetch가 끝나지 않았기 때문에 suspend됨. 리액트는 이 컴포넌트도 건너뛰고 다른 렌더링할 컴포넌트를 찾음.<Suspense>
의 fallback을 보여줌.read()
의 데이터가 있으면 해당 컴포넌트를 렌더링함.