Santos의 개발블로그

Design Patterns - Compound component pattern 본문

Language & Framework & Library/React

Design Patterns - Compound component pattern

Santos 2023. 10. 21. 09:41

Definition

- 소프트웨어를 개발하는 과정의 반복되는 일반적인 문제들에 대해 기준이 되는 해결책을 제공하는 중요한 개념

- 소프트웨어의 특정 구현을 직접 제공하지는 않지만, 반복되는 문제 상황들을 최적화된 방법으로 해결하도록 돕는 컨셉 

 

대부분의 software 문제는 이미 예전에 누군가는 겪은 문제 -> 이를 해결하기 위해 여러 방법을 사용 -> 그 방법들 중 이런 카테고리의 문제에는 어떤 방식이 좋은지 개발자들이 후기-> 자주 사용되는 공통된 패턴

Pros

1. 함께 일하는 동료들이 같은 패턴을 알고 있을수록 좋다.
- 다른 개발자나 같은 팀에 있는 사람과 패턴으로 의사소통하면 패턴 이름과 그 패턴에 담겨있는 모든 내용, 특성, 제약 조건 등을 함께 바로 이야기가 가능

2. 패턴 수준에서 이야기하면 '디자인'에 더 오랫동안 집중할 수 있다.
- 소프트웨어 시스템을 이야기할 때 패턴을 사용하면 객체와 클래스를 구현하는 것과 자질구레한 내용에 시간을 버릴 필요가 없어서 디자인 수준에서 초점을 맞춰 작업 가능

3. 전문용어를 사용하면 개발팀의 능력을 극대화할 수 있다.
- 디자인 패턴 용어를 모든 팀원이 잘 알고 있다면 오해의 소지가 줄어 작업을 빠르게 진행 가능

Cons

1. 지나친 복잡성

디자인 패턴은 자주 사용되는 문제 해결 방법에 대한 일반적인 해결책을 제공합니다. 그러나, 이러한 패턴은 때로 지나친 복잡성을 초래할 수 있습니다. 이는 프로젝트의 복잡도를 증가시키고 코드의 가독성을 저해할 수 있습니다.

2. 과도한 추상화

디자인 패턴은 추상화를 통해 일반적인 문제 해결책을 제공합니다. 그러나, 과도한 추상화는 코드의 유지보수를 어렵게 만듭니다. 이는 새로운 개발자가 코드를 이해하기 어렵게 만들고, 수정 및 업데이트가 어렵게 만들 수 있습니다.

3. 잘못된 패턴 선택

디자인 패턴은 문제 해결을 위한 다양한 해결책을 제공합니다. 그러나, 올바른 패턴을 선택하지 않으면 문제를 해결하기 어려울 수 있습니다. 이는 잘못된 패턴 선택으로 인해 코드가 복잡해지고 가독성이 저하될 수 있다는 것을 의미합니다.
 

Render Props or HOC Pattern이 궁금하다면? 
 

React Render Props and HOC 이해하기

* 이 글은 Understanding React Render Props and HOC 번역하였습니다. Understanding React Render Props and HOC A detailed introduction to Render Props and Higher-Order Components in React blog.bitsrc.io React에서 Higher-Order-Components와 Render

sangcho.tistory.com

 

Compound component pattern

- Select과 Option 컴포넌트들과 같이 부모와 자식컴포넌트의 조합으로 이루어진 복잡한 컴포넌트를 작성할 때 사용하는 패턴

- 부모와 자식 컴포넌트 간의 상태 공유를 할 때 React Context API를 사용

Example

FlyOut 컴포넌트
1. 토글 버튼과 List를 가지고 있는 FlyOut wrapper
2. List를 토글하는 Toggle 버튼
3. 메뉴 아이템을 가지고 있는 List
[보통의 순서]
1. 컨텍스트를 생성합니다.
2. 부모 컴포넌트 코드를 작성합니다.
3. 자식 컴포넌트 코드를 작성합니다.
4. 자식 컴포넌트를 부모컴포넌트의 프로퍼티로 할당합니다.

Code

1. 컨텍스트 생성 + 부모 컴포넌트

const FlyOutContext = createContext();
 
function FlyOut(props) {
  const [open, toggle] = useState(false);
 
  const providerValue = { open, toggle };
 
  return (
    <FlyOutContext.Provider value={providerValue}>
      {props.children}
    </FlyOutContext.Provider>
  );
}

- 이 컴포넌트는 상태를 가지고 있고, 모든 children에게 전달 할 toggle value를 가지고 있는 FlyOutProvider를 리턴

 

2. Toggle 자식 컴포넌트

	
function Toggle() {
  const { open, toggle } = useContext(FlyOutContext);
 
  return (
    <div onClick={() => toggle(!open)}>
      <Icon />
    </div>
  );
}

- Toggle 컴포넌트는 단순히 유저가 메뉴를 토글하기 위해 클릭할 수 있는 컴포넌트

- 토글에 관련된 이벤트만 위치, 부모에서 만든 컨텍스트를 가지고 와서 사용

const FlyOutContext = createContext();
 
function FlyOut(props) {
  const [open, toggle] = useState(false);
 
  return (
    <FlyOutContext.Provider value={{ open, toggle }}>
      {props.children}
    </FlyOutContext.Provider>
  );
}
 
function Toggle() {
  const { open, toggle } = useContext(FlyOutContext);
 
  return (
    <div onClick={() => toggle(!open)}>
      <Icon />
    </div>
  );
}
 
FlyOut.Toggle = Toggle;

- FlyOut 부모 컴포넌트와 Toggle 자식 컴포넌트를 같은 파일에 위치 

- Toggel 컴포넌트를 FlyOut 컴포넌트의 속성으로 만듬

- FlyOut이 품고있는 속성을 사용하려고 할 때, FlyOut만을 import해서 사용

	
import React from "react";
import { FlyOut } from "./FlyOut";
 
export default function FlyoutMenu() {
  return (
    <FlyOut>
      <FlyOut.Toggle />
    </FlyOut>
  );
}

 

3. List 자식 컴포넌트

function List({ children }) {
  const { open } = React.useContext(FlyOutContext);
  return open && <ul>{children}</ul>;
}
 
function Item({ children }) {
  return <li>{children}</li>;
}

- open이라는 value를 바탕으로 열리고 닫히는 값이 필요

- list 아이템을 가진 List 컴포넌트 

const FlyOutContext = createContext();
 
function FlyOut(props) {
  const [open, toggle] = useState(false);
 
  return (
    <FlyOutContext.Provider value={{ open, toggle }}>
      {props.children}
    </FlyOutContext.Provider>
  );
}
 
function Toggle() {
  const { open, toggle } = useContext(FlyOutContext);
 
  return (
    <div onClick={() => toggle(!open)}>
      <Icon />
    </div>
  );
}
 
function List({ children }) {
  const { open } = useContext(FlyOutContext);
  return open && <ul>{children}</ul>;
}
 
function Item({ children }) {
  return <li>{children}</li>;
}
 
FlyOut.Toggle = Toggle;
FlyOut.List = List;
FlyOut.Item = Item;

- FlyOut 부모 컴포넌트와 List,Item 자식 컴포넌트를 같은 파일에 위치 (위와 동일) 

- List,Item 컴포넌트를 FlyOut 컴포넌트의 속성으로 만듬 (위와 동일)

- FlyOut이 품고있는 속성을 사용하려고 할 때, FlyOut만을 import해서 사용 (위와 동일)

4. FlyoutMenu 컴포넌트

	
import React from "react";
import { FlyOut } from "./FlyOut";
 
export default function FlyoutMenu() {
  return (
    <FlyOut>
      <FlyOut.Toggle />
      <FlyOut.List>
        <FlyOut.Item>Edit</FlyOut.Item>
        <FlyOut.Item>Delete</FlyOut.Item>
      </FlyOut.List>
    </FlyOut>
  );
}

< 참고자료 >

 

[사이트] #Patterns-dev-kr

 

Home

Patterns.dev.kr 은 웹 앱의 성능을 위한 바닐라 자바스크립트와 React기반의 디자인 패턴과 컴포넌트 패턴에 대한 정보를 제공합니다.

patterns-dev-kr.github.io

[사이트] #Medium

 

리액트 디자인 패턴 2가지

렌더 프롭스 패턴, 컴파운드 컴포넌트 패턴

namunamu1105.medium.com

<React> Design Patterns - Compound component pattern end

'Language & Framework & Library > React' 카테고리의 다른 글

useEffect 완벽 가이드 2편  (1) 2023.10.29
useEffect 완벽 가이드 1편  (1) 2023.10.29
Re-rendering과 memoization  (2) 2022.03.13
컴포넌트 Re-rendering을 피하는 5가지 방법  (0) 2022.03.13
React vs Vue  (2) 2021.07.13
Comments