children prop을 활용하여 컴포넌트 합성하기

hoon·2023년 5월 1일
0

이번에는 children prop을 활용하여 React 프로젝트에서 공통 모달 컴포넌트를 분리하고 각각의 컴포넌트를 합성해보자.

기존에는 서로 다른 두 개의 모달 컴포넌트, LoginModalSignupModal 가 각각 모달에 대한 로직 및 스타일을 내부에 정의하였다.

LoginModal

SignupModal

하지만 위의 이미지를 보면 LoginModalSignupModal은 중복되는 모달에 관련된 로직과 스타일이 많은 것을 볼 수 있다. 따라서BaseModal로 공통된 컴포넌트를 만는뒤 BaseModal 컴포넌트를 기반으로하여, LoginModalSignupModal 컴포넌트를 합성하기로 하였다.

이 과정에서 필요한 것이 바로 children prop이다. children prop은 React에서 일반적으로 사용되는 방법으로, 공통 컴포넌트를 분리하고 재사용하기 위해 사용된다. BaseModal과 같은 공통 컴포넌트에서 children prop을 사용하면, 이 컴포넌트를 사용하는 곳에서 필요한 내용을 추가하거나 변경할 수 있다.

이제 프로젝트에 적용한 사례를 살펴 보자.

프로젝트 적용 사례

  1. BaseModal 컴포넌트 생성

먼저, 공통 모달 컴포넌트인 BaseModal을 생성한다. 이 컴포넌트는 공통된 모달의 레이아웃과 기본 기능을 가지며, 다른 모달 컴포넌트들이 이를 확장하여 사용할 수 있다.

// src/components/helpers/BaseModal.jsx

import React, { useRef, useEffect } from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import { palette } from '../../styles/globalColor';

// Styled-components를 사용한 스타일 정의 ...

const BaseModal = ({ isVisible, onClose, title, children }) => {
  const modalRef = useRef(null);

  const handleModalOutsideClick = event => {
    if (modalRef.current && !modalRef.current.contains(event.target)) {
      onClose();
    }
  };

  useEffect(() => {
    if (isVisible) {
      document.addEventListener('mousedown', handleModalOutsideClick);
    } else {
      document.removeEventListener('mousedown', handleModalOutsideClick);
    }

    return () => {
      document.removeEventListener('mousedown', handleModalOutsideClick);
    };
  }, [isVisible]);

  if (!isVisible) {
    return null;
  }

  return (
    <ModalContainer ref={modalRef}>
      <ModalTop>
        <CloseBtn onClick={onClose} ... ></CloseBtn>
        <h2>{title}</h2>
      </ModalTop>
      {children}
    </ModalContainer>
  );
};

BaseModal.propTypes = {
  isVisible: PropTypes.bool.isRequired,
  onClose: PropTypes.func.isRequired,
  title: PropTypes.string.isRequired,
  children: PropTypes.node,
};

export default BaseModal;
  1. SignupModal 컴포넌트에서 BaseModal 사용하기
    이제 BaseModalchildren prop을 사용하여 SignupModal의 내용을 전달한다.
// src/components/SignupModal/SignupModal.jsx

// import 내역들 ..

const SignupModal = () => {
  const isSignupModalVisible = useSelector(state => state.isSignupModalVisible);
  const dispatch = useDispatch();

  const handleHideSignupModal = () => {
    dispatch(hideSignupModal());
  };

  return (
    <BaseModal
      isVisible={isSignupModalVisible}
      onClose={handleHideSignupModal}
      title='회원가입 완료하기'
    >
      기존 SignupModalContent 컴포넌트 내역들 ..       
    </BaseModal>
  );
};

export default SignupModal;
  1. LoginModal 컴포넌트에서 BaseModal 사용하기
// src/components/LoginModal/LoginModalStyle.jsx

// import 내역들 ..

const LoginModal = () => {
  const isLoginModalVisible = useSelector(state => state.isLoginModalVisible);
  const dispatch = useDispatch();

  const handleHideLoginModal = () => {
    dispatch(hideLoginModal());
  };

  return (
    <BaseModal
      isVisible={isLoginModalVisible}
      onClose={handleHideLoginModal}
      title='로그인 또는 회원가입'
    >
      기존 LoginModalContent 컴포넌트 ...
       </BaseModal>
  );
};

export default LoginModal;

결론

  1. BaseModal이라는 공통 컴포넌트를 생성하여 모달의 레이아웃과 공통 기능을 추상화했다.
  2. children prop을 사용하여 BaseModal에 필요한 내용을 전달하여, 각각의 모달 컴포넌트에서 공통 레이아웃과 기능을 재사용할 수 있도록 했다.
  3. 이를 통해 코드의 중복을 줄이고, 유지 보수성을 향상시켰다.
profile
프론트엔드 학습 과정을 기록하고 있습니다.

0개의 댓글