ABOUT ME

Today
Yesterday
Total
  • [ Project ] React 재사용 버튼 컴포넌트 만들기
    Project 2023. 9. 1. 23:34

    - 재사용 가능한 컴포넌트

    여러 곳에서 사용되는 컴포넌트는 공통 컴포넌트로 만들어 사용하는 게 좋은 점이 많다.

    1. 반복적인 코드를 작성하는 것은 시간과 노력을 낭비하는 것이므로, 공통 컴포넌트를 만들어 재사용함으로써 중복 코드를 줄일 수 있다.

    2. 중복 코드가 많으면 동일한 로직 또는 스타일을 변경할 때 여러 위치에서 수정을 해야 할 수 있다.

    공통 컴포넌트를 사용하면 하나의 위치에서만 수정을 하면 되므로 유지 보수가 훨씬 용이하다.

    3. 요구 사항 변화나 기능 추가 시 공통 컴포넌트를 기반으로 확장하는 것이 더 쉽다. 

    등등 매우 많다. 

     

    - 버튼 컴포넌트

     

    버튼 컴포넌트는 프로젝트에서 빠질 수 없는 컴포넌트 중 하나이다.

    지난 테오의 스프린트 때 만들었던 프로젝트에서 버튼 컴포넌트를 구현했던 코드를 되짚어보고 진행 중인 프로젝트에서는 어떻게 개선할지 기록을 남기면 좋을 것 같아 글을 끄적인다.

     

    Navogue 메인 페이지

    빨간 표시한 세 종류의 버튼 컴포넌트를 하나의 공통 컴포넌트로 만들어 여러 곳에서 재사용 가능하도록 했다.

     

    // src/components/Button/style.ts
    
    import { styled } from "styled-components";
    import { ButtonStyle } from ".";
    
    const Container = styled.button<ButtonStyle>`
      cursor: pointer;
      width: ${(props) => props.width};
      height: ${(props) => props.height};
      background-color: ${(props) => (props.isClicked ? props.clickedColor : props.buttonColor)};
      border-radius: ${(props) => props.borderRadius};
      color: ${(props) => props.fontColor};
      font-size: ${(props) => props.fontSize};
      border: ${(props) => (props.borderColor ? `${props.borderWeight} solid ${props.borderColor}` : "none")};
      margin-bottom: ${(props) => props.marginBottom};
    `;
    
    export const S = {
      Container,
    };

     

    // src/components/Button/index.tsx
    
    import React from "react";
    import { S } from "./style";
    
    export interface ButtonStyle {
      width?: string;
      height?: string;
      buttonColor?: string;
      borderRadius?: string;
      borderColor?: string;
      fontColor?: string;
      fontSize?: string;
      text: string;
      borderWeight?: string;
      marginBottom?: string;
      isClicked?: boolean;
      clickedColor?: string;
    }
    
    interface IButtonProps {
      type: "SIDEBAR" | "MEMO" | "TAG" | "FILTER" | "TAG_ADD";
      text: string;
      isClicked?: boolean;
      onClick?: () => void;
    }
    
    const BUTTON_TYPE = {
      SIDEBAR: {
        width: "124px",
        height: "40px",
        borderRadius: "20px",
        borderColor: "#D8D8D8",
        buttonColor: "#FFFFFF ",
        borderWeight: "2px",
        marginBottom: "10px",
      },
      MEMO: {
        width: "104px",
        height: "47px",
        borderRadius: "30px",
        buttonColor: "#a0c9a2",
      },
      TAG: {
        width: "64px",
        height: "33px",
        borderRadius: "20px",
        buttonColor: "#EFEEEE",
      },
      FILTER: {
        width: "64px",
        height: "33px",
        borderRadius: "20px",
        borderColor: "#A0C9A2",
        buttonColor: "#FFFFFF ",
        clickedColor: "#A0C9A2",
        borderWeight: "2px",
      },
      TAG_ADD: {
        width:"33px",
        height:"33px",
        borderRadius: "20px",
        buttonColor: "#EFEEEE ",
      },
    };
    
    function Button({ ...props }: IButtonProps) {
      const style = BUTTON_TYPE[props.type] as ButtonStyle;
      return (
        <S.Container onClick={props.onClick} {...style} isClicked={props.isClicked}>
          {props.text} 
        </S.Container>
      );
    }
    
    export default Button;

     

     

    props로는 버튼의 형식, 텍스트, 이벤트 함수, 클릭여부를 받아온다.

    아래 코드와 같이 사용할 수 있다.

    <Button onClick={() => onClickBtn(e)} type={"SIDEBAR"} text={e} key={idx} />

     

    - 느낀점

    BUTTON_TYPE 객체를 컴포넌트 내부에 정의하여 컴포넌트 밖에서는 이 객체를 수정할 수 없으니 유연성, 확장성이 떨어진다. 

    스프린트 당시에는 개발 기간이 2-3일이었다.

    고로 정해진 기획에서 크게 수정되거나 변경 및 확장될 것 같지 않을 것을 판단하였고

    합성 컴포넌트를 고려하지 않았어서 컴포넌트 내부에서 버튼 타입 객체를 지정했었다.

     

    기본적인 텍스트뿐인 버튼 컴포넌트였지만 재밌었다 ! 

    앞으로 좀 더 복잡한 컴포넌트 분리를 마주할텐데 그때되면 공통 컴포넌트 2탄으로 글을 적어보겠다.

     

    개발 속도에만 집중을 하다보면 공통 컴포넌트를 추출하는 작업을 뒷전으로 미루는 경향이 있는데, 

    리팩토링에서라도 재사용 가능한 컴포넌트는 추출하여 구현하는 쪽으로 진행해야겠다.

     

     

     

     

     

Designed by Tistory.