회사에서 Presentational&container 패턴을 적용하게 되어, 정확한 개념을 공부하고, 공부하면서 알게된 사실을 정리한 글입니다.

Presentaional&container 패턴이란?

개념

  • Hook이 존재하기 전에 컴포넌트 재사용성을 높이기 위해 컴포넌트 내에서 추가적으로 레이어를 나눠 컴포넌트 간 의존도를 낮추기 위한 방법으로 등장했다.
  • 즉, 로직을 수행하는 컴포넌트와 UI를 보여주는 컴포넌트가 분리된 패턴이다.

Presentational component

  • 사용자가 직접 보고, 조작하는 컴포넌트
  • stateless : state를 직접 조작하지 않고 container component가 내려준 prop의 함수에 의해 state를 변경한다.
  • 작은 레고 블럭처럼 가능한 작게 만들어야 한다.
  • 상태를 거의 가지지 않으며, UI에 관련된 상태만 가질 수 있다.

Container component
- 어떠한 동작을 할 것인가에 대해 책임진다.
- statefull : 주로 상태를 가지고 있다.
- side effects를 만들 수 있다.
- 절대로 DOM 마크업 구조나 스타일을 가져서는 안된다.

이점

  1. presentational component의 재사용성이 뛰어나다.
    로직이 포함되어 있지 않기 때문에 다른 컴포넌트와의 의존도가 낮아 다양한 container와 조합해 재사용하기 쉽다.
  2. 앱의 기능과 UI에 대한 구분이 쉬워지므로 구조에 대한 이해가 쉬워진다.
  3. 반복되는 마크업 작업을 줄일 수 있다.
  4. 같은 state를 다른 container에게 props로 전달함으로써 상태를 공유할 수 있다.

코드예시

사용하지 않는 걸 추천합니다


이 패턴의 창시자인 Dan Abramov님이 2019년에 더 이상 이렇게 구성 요소를 분할하지 않는 것이 좋다는 말을 남기셨다. 잘 쓰고 있어서 찬양하려고 글을 쓰는 중이었는데..?

코드베이스에서 자연스럽다면 이 패턴이 유용할 수도 있지만, Hooks를 사용하면 임의의 분할 없이 동일한 작업(Hook은 로직과 표현의 분리를 가능하게 한다)을 수행할 수 있고, 필요에 의해서가 아닌 맹목적으로 사용하는 경우를 많이봤기 때문이라고 한다.

여전히 중요하다고요?

하지만 2021년에도 해당패턴이 중요한 이유를 설명한 글을 찾았다!

컴포넌트 안에서 데이터를 처리하는 로직을 사용하는 경우 컴포넌트의 재사용성이 떨어지는 것은 사실이다. 특히 특정 라이브러리와 프로그램의 아키텍처에 강하게 의존성이 생긴다. 예를 들어 react-intl 라이브러리에서 제공하는 hook을 쓰다가, react-i18n으로 라이브러리를 바꾼다면? 라이브러리리에서 제공하는 로직을 사용하는 모든 컴포넌트를 찾아 수정해야할 것이다.

presentatation 계층의 컴포넌트라면 스타일이나 Bootstrap, Material UI와 같은 라이브러리와 연결하는 것이 좋다.

Presentainal Component

  1. html, css 및 기타 프리젠테이션 구성요소만 사용할 수 있다.
  2. 다른 App에서도 사용할 수 있어야 한다. (App의 설계나 framework에 종속되지 않음)
  3. style 관련된 hook만 포함해야 한다.
  4. 고차 컴포넌트로 래핑되지 않는다. 예를 들어 리덕스를 사용한다면, 더 높은 순서의 연결 컴포넌트가 컨테이너 컴포넌트에 추가되어야 한다.
  5. 컴포넌트의 시각적 특성을 변경하는 props를 종종 허용한다.
  6. 완전히 다른 스타일 시트를 로드하는 props를 종종 허용한다.

Container Component

  1. html이나 style에 관한 것은 포함하지 않는다.
  2. presentation component나 다른 container component를 사용할 수 있다.
  3. 로직은 hook file에 들어간다. (reacdt-hooks-testing-library를 사용해 test하기 위함)
  4. Props를 받을 수 있다.
  5. Context를 사용하고, side effect를 만들고, db에 CRUD 작업을 요청할 수 있다.
  6. CRUD 작업이 성공했을 때 UI에 즉시 반영하고, 실패했을 때는 UI를 롤백한다.
  7. 항상 cotnainer 구성 요소에서 테스트 ID를 선언하고 구성 요소에 테스트 ID를 전달한다.

정리

회사에서도 함수형 컴포넌트와 Hook을 사용했고, container도 unstated-next가 제공하는 hook을 이용해 container를 만들었다.
개념적으로 view와 데이터 관련 로직을 분리했지만, container component가 아닌 context에 관련 로직을 작성했다.

그렇게 함으로써 컴포넌트의 재사용성이 높아졌고, 불필요한 컴포넌트의 수를 줄일 수 있었다. 예를 들어 영화목록 페이지라고 하면
Movie Page > Movie Table 컴포넌트 = 데이터 로직 + table 컴포넌트 로직 으로 구성했다면
Movie Page + Container --props--> table 컴포넌트 로 구성을 할 수 있다.

그리고 구조적으로도 파악하기 쉽고 presentatonal component가 깔끔해졌다.
Container가 복잡해지는 문제가 있지만 관심사에 따라 Container를 분리하면 될 것 같다.

이번 내용을 정리하면서 Presentational - container pattern의 개념과 등장배경에 대해 알 수 있었고, Hook과 ContextAPI에 대해 더 공부해야겠다고 느꼈다.


reference

'React' 카테고리의 다른 글

나만의 React 라이브러리 만들기  (0) 2022.01.18
리액트에서 Variable과 State의 차이가 뭘까?  (0) 2022.01.13
React Query  (0) 2021.07.09

+ Recent posts