1. 카페에서 음료를 주문하는 것처럼


React에서 데이터를 가져오는 방법에 대해 얘기하면 반드시 등장하는 두 개념이 있다. WaterfallParallel이다. 이 두 개념은 단순히 "빠르고 느린 것"의 차이가 아니라, React의 렌더링 구조 자체에서 비롯된 문제이다.

이 글은 카페에서 음료를 주문하는 상황을 실로 꿰어서, Waterfall이 왜 발생하고 Parallel로 바꾸면 어떤 구조적 변화가 일어나는지, 그리고 실제로 어떤 방법으로 해결할 수 있는지를 설명하자.

2. Waterfall — 카운터 직원의 주문 방식


2-1) 카페에서 본 Waterfall

카페에서 음료를 주문하는 상황을 떠올려보자. 카운터 직원이 손님에게 "아메리카노 주문받아드립니다"라고 하고, 아메리카노를 만들어서 건네준 후에야 "수정과도 주문하실 건가요?"라고 물어보는 것이다.

두 음료는 완전히 독립적으로 만들 수 있는 주문이지만, 직원이 하나씩 순차적으로 처리하는 구조 때문에 손님의 총 대기 시간은 아메리카노 제작 시간 + 수정과 제작 시간이 된다. 아메리카노가 완료되지 않을 때까지는 수정과의 존재조차 알지 못한다.

이것이 React에서 발생하는 Waterfall과 정확히 같은 구조이다.

2-2) React에서도 동일한 구조

React는 컴포넌트 트리를 위에서 아래로 순차적으로 렌더한다. 부모가 완료되어야 자식이 mount된다. 그리고 각 컴포넌트가 자신의 데이터를 useEffect로 가져오는 구조라면, 렌더 순서 자체가 fetch 순서가 된다.

컴포넌트 트리:

  App
  └── Layout
      └── UserProfile        ← fetchUser
          └── UserPosts      ← fetchPosts
              └── PostComments  ← fetchComments

카페로 치면 이렇다. UserProfile은 아메리카노, UserPosts는 수정과, PostComments는 주스이다. 직원이 아메리카노를 만들고 건네준 후에야 수정과를 만들고, 수정과를 건네준 후에야 주스를 만드는 것이다.

시간축으로 그으면:

시간축 (Waterfall):

  UserProfile mount  → fetchUser 시작
  ..................... fetchUser 완료
                        UserPosts mount  → fetchPosts 시작
                        ................. fetchPosts 완료
                                          PostComments mount → fetchComments 시작
                                          .................. fetchComments 완료

  총 로딩 시간 = fetchUser + fetchPosts + fetchComments

Network 탭에서도 이렇게 보인다.