(React) 리액트 기초 12. 버튼 구현 - ② Refactoring styled components

2023. 7. 10. 10:14

지난 포스팅에서 버튼 6개에 대해서 리뷰 겸 해석하는 글을 썼었는데, 나머지 버튼 그룹 (Input, Modal, Select)를 마저 써보려고 한다. 그 전에 기존 코드를 대폭 리팩토링한 부분이 있어서 Button 그룹을 먼저 다시! 리뷰해보자 😫

Button 그룹

처음에는 스타일드 컴포넌트를 <StLarge> <StMedium> <StSmall>로 사이즈별로 나눈 뒤 색상을 1:1로 변경하는 방식으로 코드를 작성했었다. 이번에는 그대신에 <StBtn>이라는 하나의 스타일드 컴포넌트로 여섯개의 버튼을 한꺼번에 해결해봤다.

먼저 모든 버튼태그의 기본이 될 <StBtn> : 


  export const StBtn = styled.button`
    box-sizing: border-box;
    border: none;
    font-weight: 600;
    border-radius: 8px;
    cursor: pointer;
    &:active {
        filter: brightness(70%);
    }
     ${props => colorHandler(props.$bgColor)}; 

    ${({ $bgColor }) => colorHandler($bgColor)};
    ${({ type }) => sizeHandler(type)};
`;

버튼에 공통적으로 적용할 부분 (box-sizing~active)까지는 그대로 두고, 그 후에 props로 내려주면서 변경하고 싶은 부분을 작성했다.

공통 적용 부분 중에서 active~도 바뀌었는데, 기존에는 변경하고자 하는 색상을 직접 지정해서 &:active{background-color: 특정컬러}로 작성했었다면, 이번에는 filter:brightness(퍼센트)로 밝기조절을 하는 방식으로 바꿨다. 이렇게 하면 번거롭게 색상을 지정해줄 필요가 없고 공통적으로 적용할 수 있어서 훨씬 편리하다. 이때 퍼센트는 0에 가까워질수록 어둡고 100에 가까워질수록 밝아진다. 
이외에도 &:active{filter : opacity(0~1)}로 투명도를 조절할 수 있다. 0은 투명도가 100%라서 클릭할때 사라지는 것 처럼 보이고, 1이면 변화가 없는 것 처럼 보인다. 
만약에 클릭했을 때 테두리나 배경, 글자색상의 밝기만 조절하고 싶다? &:active{변경하고싶은부분 : rgba(0,0,0,0.5)} 에서 세번째 0 다음 소수점으로 가능하다. 

 ${({ $bgColor }) => colorHandler($bgColor)}; 부분은 props로 colorHandler의 bgColor를 받아오고 있는데, bgColor의 앞에 있는 달러기호($)는 일단 넘기고 생각해보자.

${({ bgColor }) => colorHandler(bgColor)}; 는  ${props => colorHandler(props.bgColor)}; 를 구조분해 할당한 것이다. 이걸 이해하기 위해서 우선 colorHandler를 살펴보자. 


 const colorHandler = color=> {
    switch (color) {
        case 'green':
            return `border: 3px solid rgb(85, 239, 196); background-color: rgb(85, 239, 196)`;
        case 'pink':
            return `border: 3px solid rgb(250, 177, 160); color: rgb(214, 48, 49); background-color: rgb(250, 177, 160)`;
        default:
            return '';
    }
};

colorHandler는 bgColor에 따라서 border, background-color를 바꿔주는 switch 조건문을 실행시키는 함수다.
이때 color는 단순한 parameter므로 변경해도 상관없다.  

<StBtn $bgColor={'green'} type="medium">

부모 함수 return 이하에서 StBtn을 보면, bgColor={'type'} 부분에서 props를 스타일드 컴포넌트로 내려주고 있다. ${props => colorHandler(props.bgColor)}는 props로 내려준 bgColor를 colorHandler함수로 실행시켜주고 있다. 즉, type이 green인 경우  `border: 3px solid rgb(85, 239, 196); background-color: rgb(85, 239, 196)`; 이라는 스타일드를 리턴해준다. 만약 부모 컴포넌트에서 type이 따로 지정되지 않으면 default값인 '', 즉 아무런 스타일드도 적용하지 않는다. 

아까 일단 넘어가자고 했던 bgColor앞에 $기호는 개발자모드에서 확인할 수 있는 오류를 해결하기 위해서 붙여준건데, 이 오류다.

styled-components: it looks like an unknown prop "bgColor" is being sent through to the DOM, which will likely trigger a React console error. If you would like automatic filtering of unknown props, you can opt-into that behavior via `<StyleSheetManager shouldForwardProp={...}>` (connect an API like `@emotion/is-prop-valid`) or consider using transient props (`$` prefix for automatic filtering.) 

해석해보자면 bgColor라는 알려지지 않은 prop이 DOM으로 보내지고 있는데, 에러가 될 수 있으니 필터링을 해줘야 한다. 그러기 위해서는 '$'를 붙여달라고 한다. 이때 접두사 $는 은닉 역할을 하는데, bgColor처럼 일시적으로 내려주기 위해 만든 transient props를 사용할 때, 알 수 없는 속성이 DOM으로 전달되는 것을 숨기는 역할을 한다. 즉, 접두사$를 붙여서 bgColor가 DOM으로 전송되는 일을 막아주기 때문에 에러가 발생하지 않게 된다. 이때 $는 템플릿 리터럴과는 다르니 혼동하지 말아야한다.

${({ type }) => sizeHandler(type)};도 똑같다.

<StBtn bgColor={'green'} type="medium">
  const sizeHandler = parameter => {
    switch (parameter) {
        case 'large':
            return `width: 200px; height: 50px; background-color: white; font-weight: 600;`;
        case 'medium':
            return `width: 130px; height: 45px;`;
        default:
            // Small
            return `width: 100px; height: 40px;`;
    }

sizeHandler는 StBtn props에서 내려받은 type 이하의 스타일을 리턴하는 함수다.
${{ type } => sizeHandler (type) } 은 ${(props)=> sizeHandler(props.type)}를 구조분해할당한 것이다.

 

여기까지, 기존 코드와 기능적으로는 동일하지만 훨씬 간결하고 가독성이 좋은 코드로 변신했다! 🥰