Skip to content

컴포넌트 재사용성을 높여보자: Modal 분리기

Soobeen Yoon edited this page Dec 15, 2022 · 8 revisions

기존 TodoModal.tsx

  • 신규 todo 추가 및 수정까지 모두 담당하는 슈퍼 컴포넌트!
    • 수정, 추가, validation check 등 수많은 로직들과 자식 컴포넌트들, 스타일까지 모두 가지고 있음.
    • 컴포넌트 단위의 개발의 목적인 재사용성, 관심사의 분리, 응집도 있는 로직, 변경에 대한 유연성이 모두 어려워지고, table 외 다른 페이지에서 사용하기 어려워짐
스크린샷 2022-12-14 오후 8 45 29

🧐 이대로는 안 되겠다.!!

변경이 필요한 이유

1. 스타일, 로직이 결합된 거대한 컴포넌트

컴포넌트는 사용자와의 인터렉션을 통해 필요한 비즈니스 로직을 실행하거나 스타일, 애니메이션과 같은 시각적인 부분을 표현하는 UI(User Interface)를 적절하게 나눈 것

  • TableModal은 비즈니스 로직, 스타일, UI 모두 들어있다..
  • validation check, save, create, edit, style 모두 들어있는 구조로, 컴포넌트 단위의 개발이라는 철학에 부합하지 않음.

2. 의존성 관리에 대한 필요성

매우 많은 컴포넌트를 수정해야 하는 경우, 또는 해당 변경 사항이 생겼을 때 어떤 컴포넌트를 수정해야 하는지 분명하게 알 수 없는 경우 의존성 관리를 해야 한다.

  • 불행하게도 TableModal은 재사용이 어려울뿐만 아니라, 새로운 input이 생겼을 때 수정하는 부분에 대한 부담도 커져버렸다.
  • 또한 table 외의 다른 페이지에서 사용이 복잡해졌고, 새로운 형태의 Modal 개발 시 처음부터 Modal을 선언해야 하는 문제가 생겼다.

그러면 컴포넌트를 어떻게 나누면 좋을까?

1. 추상화

  • TableModal을 EditModal, CreateModal로 분리하여 불필요한 분기를 없앰.
    • 기존에는 Edit, Create를 한 컴포넌트에서 수행했기 때문에 로직 중에 if로 분기하는 부분이 매우 많았음.
    • 단적인 예로, 부끄럽지만 기존 modal에서는 modalType에 따라 제목을 분기하여 처리하는 useEffect를 사용했는데, 타입별 분리를 통해 제목을 props로 전환할 수 있었다.
  useEffect(() => {
    if (modalType === create) {
      return setModalHeader('할 일 추가하기');
    }
    if (modalType === update) {
      setInitData();
      return setModalHeader('할 일 수정하기');
    }
    setModalHeader(none);
  }, [modalType]);
  • 이러한 EditModal, CreateModal의 상위에 모달이라면 꼭 필요한 기능들을 <Modal>로 분리했다.
    • Style, Overlay 및 버튼 클릭 이벤트들

2. 의존성 관리

의존성 관리의 가장 큰 줄기는 불필요한 의존성을 제거하거나 약화시키고, 불가피하게 강하게 의존되는 요소들은 가깝게 두는 것에 있다.

  • Modal은 Overlay와 강하게 의존이 필요하기 때문에, Modal Component 안에 Overlay 컴포넌트를 넣음으로써, 결합을 강화시켰다.
const Modal = ({ modalHeader, action, setIsModalOpen, children }: ModalProps): ReactElement => {
  const modalWrapper = useRef();

  // 생략

  return (
    <OverLay setHasModal={setIsModalOpen}>
      <Wrapper ref={modalWrapper}>
        // 생략
      </Wrapper>
    </OverLay>
  );
};

export default memo(Modal);

3. Custom Hook, util 파일로 비즈니스 로직 분리

  • 먼저, validation check 등 컴포넌트 내부에 없어도 되는 로직을 util 파일로 분리했다.
  • 컴포넌트에서 Todo 변경 시 update를 위해 수행하던 로직을 Custom Hook (useModalComplete.ts)로 분리했다.
  • 이에 따라, CreateModal, EditModal은 Modal에 action을 전달하여 각각의 역할에 맞는 submit action을 수행할 수 있도록 하였다.
  • 아래는 CreateModal을 간략화한 예시이다.
const CreateModal = () => {
  const [setComplete] = useModalComplete(MODAL_CREATE);

  return (
    <CreateModal>
      <Modal action={setComplete} />
    </CreateModal>
  )
};

최종 결과

  • 하나의 파일이 총 5개의 파일로 분리되어 모달 로직, 비즈니스 로직, 스타일으로 나누어 분리하게 됨.
스크린샷 2022-12-14 오후 8 45 51

다이어그램 페이지에 새로운 Modal을 도입한 팀원 A씨의 생생 리얼 후기

스크린샷 2022-12-14 오후 9 53 00

매우 만족하신 것 같아 뿌듯합니다 ^^

느낀점

  • Modal이라는 공용 컴포넌트를 만든 덕분에 추상화, 분리, 재사용 등 측면에서 많은 것을 배울 수 있었다.
  • 다만, 비즈니스 로직 자체, 특히 validation check하는 부분은 edit과 create가 여전히 같이 사용하고 완전히 분리해내지 못해서 이를 함수 단위로 쪼개면 더 좋을 것 같다는 피드백을 받았다.!!

PR 구경하기

FEAT: modal component 분리

참고자료

💊 비타500

📌 프로젝트

🐾 개발 일지

🥑 그룹활동

🌴 멘토링
🥕 데일리 스크럼
🍒 데일리 개인 회고
🐥 주간 회고
👯 발표 자료
Clone this wiki locally