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()의 데이터가 있으면 해당 컴포넌트를 렌더링함.