아래 출처의 글을 보고 번역 및 주요 내용을 정리한 글입니다.
- 어떻게 하면 다양한 경우에 적합한 재사용 가능한 컴포넌트를 build할 수 있을까?
- 어떻게 하면 사용하기 쉽게 단순한 API와 컴포넌트를 만들 수 있을까?
- 어떻게 하면 UI와 기능적으로 확장 가능한 컴포넌트를 만들 수 있을까??
에 대한 고민으로 이 글은 시작합니다.
5가지의 패턴을 제시하고 장점, 단점을 리스트업 해줍니다.
그리고 두개의 기준을 명시해 주었습니다.
- 제어의 역전 : 컴포넌트를 사용하는 사람들에게 제공되는 유연성과 주도권의 정도
- 구현의 복잡도 : 해당 패턴을 구현하는데 복잡도
1. Compound Components Pattern
이 패턴은 prop drilling을 피하면서 선언적으로 컴포넌트를 구성할 수 있게 해줍니다. 이해가 쉬운 api와 관심사의 더 나은 분리와 함께, customizable 컴포넌트를 만들고 싶다면 이 패턴을 고려하세요
장점
* api의 복잡도 감소: 거대한 부모 컴포넌트에 props들을 묶어서 보내지 않고 자식 ui 컴포넌트에 prop drilling을 피할 수 있ㄷ습니다. 대신 Counter's의 자식들에 prop들이 매칭되므로 더 이해하기 쉽습니다
* 유연한 마크업 구조: 다양한 경우의 대응과 함께 좋은 ui 유연성을 제공하빈다. 예를 들면, Counter's의 자식들의 순서를 쉽게 변경하거나 어떻게 보일것인지를 결정할 수 있습니다.
* 관심사의 분리: 대부분의 로직은 Counter에 집중됩니다. 하나의 context(CounterProvider + useCounterContext)가 Counters' 자식들에게 상태(counter)와 handler(handleIncrement(), handleDecrement())를 다루기 위해 사용됩니다.
책임의 분배를 더 명확히 해줍니다.
단점
* 너무 높은 ui 유연성 : 이 정도의 유연성은 애초에 기대하지 않았던 상황을 초래할 수 있습니다(i.e: 원하지 않던 코드, Counter's 자식들의 잘못된 순서, 필수 자식들의 실종). 상황에 따라 너무 많은 유연성을 원하지 않을 수 있습니다.
* 비대해진 JSX: jsx의 크기를 증가시킵니다. eslint를 쓰거나 prettier를 쓰면 더더욱 그러할 것입니다. 하나의 컴포넌트에서는 미미해보일 수 있지만, 전체 큰 그림에서 보게되면 큰 차이가 있을 수 있습니다
기준
* 제어의 역전 : 1/4
* 구현의 복잡도 : 1/4
이 패턴을 사용하는 라이브러리
* React Bootstrap
* Reach ui
2. Control Props Pattern
* 이 패턴은 컴포넌트를 제어 컴포넌트로 만듭니다. 외부 상태는 컴포넌트의 기본 동작을 수정할 수 있는 로직을 넣을 수 있는 "single source of truth"로 동작합니다.
장점
* 더 많은 제어권: 개발자가 주요 상태를 제어할 수 있기 때문에, Counter의 동작에 직접 영향을 줄 수 있습니다.
단점
* 구현의 복잡도: 이전에는 하나의 통합된 부분으로 컴포넌트의 동작이 충분했습니다. 이제는 3개의 다른 부분이 존재 합니다.
기준
* 제어의 역전: 2/4
* 구현의 복잡도: 1/4
이 패턴을 사용하는 라이브러리
* Material UI
3. Custom hook Pattern
* 제어의 역전에서 나아가 보자: 주요 로직은 커스텀 훅 내부에 위치합니다. 이 훅은 몇몇 내부 로직으로 구성되어있고 개발자에게 좋은 제어권을 제공합니다.
장점
* 더 많은 제어권: 개발자는 Counter 동작을 수정하면서, useCounter와 Counter 사이에 커스텀 로직을 더 부여할 수 있습니다.
단점
* 구현의 복잡도: 로직 부분이 render 부분과 분리되었기 때문에 개발자는 두 군데를 신경써야 합니다. Counter가 어떻게 동작하는지 잘 이해하는 것이 이 패턴을 수행하기 위해 필수 입니다.
기준
* 제어의 역전 : 2/4
* 구현의 복잡도 : 2/4
이 패턴을 사용하는 라이브러리
* React table
* React hook form
4. Props Getters Pattern
* Custom Hook Pattern은 더 나은 제어권을 제공하지만 로직을 재생성해야 하고 원래 hook의 props를 다루어야 하기 때문에 컴포넌트의 통합을 어렵게 합니다.
Props Getters Pattern 패턴은 이러한 복잡도를 다루기 위해 시도합니다. props들을 노출시키는 대신에 getters들을 제공합니다.
getter은 많은 prop들을 반환하는 함수 입니다. 의미있는 이름을 가지고 있고 jsx 요소에 어떤것이 대응하는지 명확히 할 수 있습니다.
장점
* 쉬운 사용: 복잡도는 숨겨져 있습니다. useCounter에서 제공하는 getter를 jsx 요소에 알맞게 연결하기만 하면 됩니다.
* 유연성: getter를 특별한 경우에 오버로딩 할 수 있습니다.
단점
* 가독성의 저하: getters는 컴포넌트를 통합하기 수월하게 하는 추상화를 제공해 주지만 좀 더 모호합니다. 개발자는 getter props들을 잘 이해하고 있어야 하고 영향 받는 로직들을 오버라이드 하기 위해 적절히 이해하고 있어야 합니다.
기준
* 제어의 역전: 3/4
* 구현 복잡도: 3/4
이 패턴을 사용하는 라이브러리
* React table
* Downshift
5. State reducer Pattern
제어의 역전에서 가장 발전된 패턴이빈다. 컴포넌트가 내부적으로 컴포넌트가 작동하는 방식을 변경할 수 있는 더 나은 방법을 제공합니다. Custom Hook Pattern과 유사하지만 hook을 위해 reducer를 제공해야 합니다. 이 reducer는 컴포넌트의 어떠한 내부 동작이라도 오버로드 할 수 있습니다.
장점
* 더 많은 제어권 : 복잡한 경우 state reducer의 사용이 개발자에게 제어권을 주기 가장 좋은 방법입니다. useCounter's의 모든 내부 동작은 밖에서 접근이 가능하고 override될 수 있습니다.
단점
* 구현의 복잡도: 이 패턴은 구현하기 가장 복잡합니다
* 가독성의 저하: reducer의 내부 동작이 변경될 수 있기 때문에 컴포넌트 내부 로직의 높은 이해가 필수 입니다.
기준
* 제어의 역전: 4/4
* 구현 복잡도: 4/4
이 패턴을 사용하는 라이브러리
* Downshift
결론
* 5개의 React 패턴들을 통해 제어의 역전 측면에서 이점을 가지는 방법들을 살펴 보았습니다. 유연하고 확장가능한 컴포넌트를 만드는 강력한 방법들을 제공합니다.
그러나, "큰 힘에는 큰 책임이 따른다"라고 알고 있듯이, 개발자에게 더 많은 제어권이 주어지면, "plug and play" 방식에서 컴포넌트는 더 멀어질 수 있습니다. 이것이 적절한 패턴을 적절한 경우에 사용하여야 하는 이유입니다.
아래의 그림은 제어의 역전과 구현 복잡도에 따라 패턴을 분류한 그림입니다.
출처: https://javascript.plainenglish.io/5-advanced-react-patterns-a6b7624267a6
'Frontend > React' 카테고리의 다른 글
[번역] React Atomic하게 바라보기 (0) | 2024.05.19 |
---|---|
React 공식문서 주요개념 살펴보기 (0) | 2022.05.26 |
React what is JSX? (번역글) 🤔 (0) | 2022.04.27 |
React One Simple trick to optimize React re-renders (번역글) 🤔 (0) | 2022.04.27 |
React The State Reducer Pattern with React Hooks (번역글) 🤔 (0) | 2022.04.24 |