[React] 컴파운드 컴포넌트 패턴

Empu·2024년 9월 8일

react

목록 보기
1/6

디자인 패턴 적용 이유

-> Compound component 패턴에 대해 설명하기 전, 프론트엔드에서 디자인 패턴이 필요한 이유를 먼저 설명하고자 한다.

시간이 지날수록 웹 어플리케이션은 점점 복잡해지고 고도화되고 있다. 또한 UX 개선, 다양한 디바이스 대응등 프론트엔드가 해결해야할 과제들은 늘어나고 있다. 웹 어플리케이션의 복잡성이 늘어나고 있는데, 이를 해결하지 못한다면, 유지보수가 힘들고 성능이 저하될 가능성이 높다. 이를 해결하는 방법 중 한개가 디자인 패턴이다.

Compound Components Pattern

→ 혼자 동작하지 않고 연결된 합성 컴포넌트

합성 컴포넌트

ex) select 태그와 option 태그는 같이 사용되게 구성되어 있다(리액트를 벗어난 관점)

합성을 해서 뭐해?

“ 합성을 사용하여 컴포넌트 간에 코드를 재사용 하는 것이 좋다 ”

SRP(단일 책임 원칙)

  • 관심사 분리

합성 컴포넌트 패턴 적용 이유

  • Props drilling 문제를 해결 할 수 있다.

  • 선언적이고 이해하기 쉬운 컴포넌트를 작성할 수 있다.

  • UI 구조를 유연하게 변경할 수 있다.

  • ex) Accordion

단점

  • 코드가 길어진다.
  • 아이러니하게 가독성 또한 장점이자 단점이 될 수 있다.

실제 코드로 컴파운드 패턴 이해하기

  • App.ts
import { Accordion } from './components/Accordion/Accordion';

function App() {
  return (
    <main>
      <section>
        <h2>Why work with us?</h2>
        <Accordion className="accordion">
          <Accordion.Item id="experience" className="accordion-item">
            <Accordion.Title className="accordion-item-title">
              we got 20 years of experience
            </Accordion.Title>
            <Accordion.Content className="accordion-item-content">
              <article>
                <p>You cant go wrong with us.</p>
                <p>We are hiring</p>
              </article>
            </Accordion.Content>
          </Accordion.Item>
          <Accordion.Item id="local-guides" className="accordion-item">
            <Accordion.Title className="accordion-item-title">
              we're working with local guides
            </Accordion.Title>
            <Accordion.Content className="accordion-item-content">
              <article>
                <p>You cant go wrong with us.</p>
                <p>We are hiring</p>
              </article>
            </Accordion.Content>
          </Accordion.Item>
        </Accordion>
      </section>
    </main>
  );
}

export default App;
  • Accordion.ts
import { createContext, useState, useContext } from 'react';
import AccordionItem from './AccordionItem';
import AccordionContent from './AccordionContent';
import AccordionTitle from './AccordionTitle';

const AccordionContext = createContext();

export function useAccordionContext() {
  const ctx = useContext(AccordionContext);

  if (!ctx) {
    throw new Error('Error!');
  }
  return ctx;
}

export function Accordion({ children, className }) {
  const [openItemId, setOpenItemId] = useState();
  function toggleItem(id) {
    setOpenItemId((prev) => (prev === id ? null : id));
  }
  const contextValue = {
    openItemId,
    toggleItem,
  };
  return (
    <AccordionContext.Provider value={contextValue}>
      <ul className={className}>{children}</ul>
    </AccordionContext.Provider>
  );
}

Accordion.Item = AccordionItem;
Accordion.Title = AccordionTitle;
Accordion.Content = AccordionContent;

Context Api 사용하기

  • 컴파운드 컴포넌트 패턴을 사용할때 context api를 자주 사용한다
  • 위의 코드를 예시로, 현재 선택된 id 값을 알아야하고 다른 컴포넌트들에게 공유하기 위해서 상태를 관리해야한다.

함수 객체에 속성 추가하기

Accordion.Item = AccordionItem;
Accordion.Title = AccordionTitle;
Accordion.Content = AccordionContent;
  • App 단에서 Accordion 컴포넌트만 import 할 수 있는 이유이다.
  • 컴포넌트간의 명확한 분리가 가능하다.
  • 유연하게 구조를 만들 수 있다.
profile
Life is a risk.

0개의 댓글