재사용 가능한 버튼 컴포넌트 만들기 (TypeScript, Emotion)

Eunhye Kim·2024년 1월 8일
0

이렇게 5가지의 버튼이 있을 때, 필요할 때 마다 스타일을 주는 방법도 있지만, 재사용 가능한 버튼 컴포넌트를 하나 만들어서 스타일 별로 재활용할 수 있는 방법도 있다.

1. 타입 프로퍼티를 사용하여 스타일드 컴포넌트에 속성을 전달하기

type ButtonStyleProps = {
  state: "normal";
  size: "small" | "medium";
  colorType: "black" | "white" | "brown";
};

const ButtonStyle = styled.button<ButtonStyleProps>`
  border-radius: 5px;
`;

interface BunttonProps extends ButtonStyleProps {
  children: React.ReactNode;
  onClick?: () => void;
}

const Button = ({ children, onClick, ...styleProps }: BunttonProps) => {
  return (
    <ButtonStyle {...styleProps} onClick={onClick}>
      {children}
    </ButtonStyle>
  );
};

export default Button;

ButtonStyleProps라는 타입을 선언하고, 이 타입을 가지는 속성들을 받아 Emotion의 컴포넌트의 속성으로 사용하고 있다.
타입 프로퍼티를 사용하는 이유는 코드를 읽거나 유지보수하기 쉽게 하기 위함이다.
나는 small사이즈, medium사이즈, black컬러, white컬러, brown컬로 로 정해두었다.

2. 스타일 적용

buttonSize와 buttonType의 맞게 스타일을 정의할 필요가 있다.
예를 들면, 버튼 사이즈가 small이면 width: 50px으로 버튼 컬러가 black이면 background-color가 background-color: #000으로 이런 식으로 줄 수 있다.

2-1. 컬러 별 버튼 스타일

export const backButtonColorOfState = {
  normal: css`
    background-color: #000;
    color: #fff;
    &:hover {
      background-color: #535050;
    }
  `,
};

export const whiteButtonColorOfState = {
  normal: css`
    background-color: #fff;
    color: #000;
    border: 1px solid #7a7979;

    &:hover {
      background-color: #f8f8f8;
    }
  `,
};

export const brownButtonColorOfState = {
  normal: css`
    background-color: ##4d100f;
    color: #fff;
    &:hover {
      background-color: #5f3837;
    }
  `,
};

마지막으로 buttonType 이라는 객체로 정리해두자

export const buttonType = {
  black: backButtonColorOfState,
  white: whiteButtonColorOfState,
  brown: brownButtonColorOfState,
};

2-2. 버튼 크기 정하기

small이면 width: 50px으로 medium이면 width: 150px으로 사이즈를 다르게 주었다.

export const buttonSize = {
  small: css`
    width: 50px;
    height: 30px;
  `,
  medium: css`
    width: 150px;
    height: 30px;
  `,
};

3. ButtonStyle에 적용하기

const ButtonStyle = styled.button<ButtonStyleProps>`
  border-radius: 5px;

  ${(props) => buttonSize[props.size]}
  ${(props) => buttonType[props.colorType]?.[props.state]}
`;

처음에 정의한 ButtonStyle에 buttonSize와 buttonType를 적용시키자.

4. 컴포넌트 사용하기

import Button from "@components/components/button";

  return (
    <Button size="small" state="normal" colorType="black>
    다음
    </Button>

    <Button size="small" state="normal" colorType="brown">
    완료
    </Button>
 )

컴포넌트를 사용을 할 때 props로 size와 state, colorType을 넘겨주면 위에서 정의한 스타일이 적용이 된다.


전체 코드

  • index.tsx
import React from "react";
import styled from "@emotion/styled";
import { buttonSize, buttonType } from "./style";

type ButtonStyleProps = {
  state: "normal";
  size: "small" | "medium";
  colorType: "black" | "white" | "brown";
};

const ButtonStyle = styled.button<ButtonStyleProps>`
  border-radius: 5px;

  ${(props) => buttonSize[props.size]}
  ${(props) => buttonType[props.colorType]?.[props.state]}
`;

interface BunttonProps extends ButtonStyleProps {
  children: React.ReactNode;
  onClick?: () => void;
}

const Button = ({ children, onClick, ...styleProps }: BunttonProps) => {
  return (
    <ButtonStyle {...styleProps} onClick={onClick}>
      {children}
    </ButtonStyle>
  );
};

export default Button;
  • style.ts
import { css } from "@emotion/react";
import theme from "@components/lib/styles/theme";

export const buttonSize = {
  small: css`
    width: 50px;
    height: 30px;
  `,
  medium: css`
    width: 150px;
    height: 30px;
  `,
};

export const backButtonColorOfState = {
  normal: css`
    background-color: ${theme.color.black};
    color: ${theme.color.white};
    &:hover {
      background-color: #535050;
    }
  `,
};

export const whiteButtonColorOfState = {
  normal: css`
    background-color: ${theme.color.white};
    color: ${theme.color.black};
    border: 1px solid #7a7979;

    &:hover {
      background-color: #f8f8f8;
    }
  `,
};

export const brownButtonColorOfState = {
  normal: css`
    background-color: ${theme.color.brown};
    color: ${theme.color.white};
    &:hover {
      background-color: #5f3837;
    }
  `,
};

export const buttonType = {
  black: backButtonColorOfState,
  white: whiteButtonColorOfState,
  brown: brownButtonColorOfState,
};
profile
개발에 몰두하며 성장하는 도중에 얻은 인사이트에 희열을 느낍니다.

0개의 댓글