본문 바로가기
웹/프론트엔드

[React/Typescript] html 태그의 기본 props를 사용해 컴포넌트를 만드는법

by 이민훈 2022. 7. 16.

문자열과 onClick 함수를 props로 전달받는 Button 컴포넌트를 만든다고 가정하면 아래와 같은 컴포넌트를 만들어 쓸 수 있습니다.

 

interface ButtonProps {
  children: string;
  onClick: () => void;
}

const Button = ({ children, onClick }: ButtonProps) => {
  return <button onClick={onClick}>{children}</button>;
};

export default Button;

 

그리고 아래와 같이 불러다 쓸 수 있겠죠?

 

import Button from "components/Button";

const App = () => {
  return <Button onClick={() => console.log("Button Clicked")}>Button</Button>;
};

export default App;

 

하지만 button이라는 html tag에는 onClick이라는 prop이 이미 존재하고, 그 외 다양한 prop도 있습니다.

 

onClick 외에도 다양한 이벤트 핸들러 prop도 존재하고, style prop을 통해 인라인 스타일을 지정할 수도 있죠.

 

button 태그의 기본 props들을 확장하여 버튼 컴포넌트를 만들 수 있다면 좀 더 범용성이 넓은 컴포넌트를 만들 수 있지 않을까요?

 

interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {}

const Button = (props: ButtonProps) => {
  return <button {...props} />;
};

export default Button;

 

위 코드처럼 컴포넌트를 만들어 준다면,

 

button 태그의 기본 props들을 확장하여 컴포넌트를 만든 경우

 

button 태그의 기본적인 props들은 물론이고,

 

interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
  additionalProps: string;
}

const Button = (props: ButtonProps) => {
  console.log(props.additionalProps);
  return <button {...props} />;
};

export default Button;

 

추가적으로 필요한 props들을 받을 수 있게 됩니다.

 

import Button from "components/Button";

const App = () => {
  return (
    <Button additionalProps="Hello World" onClick={() => console.log("Button Clicked")}>
      Button
    </Button>
  );
};

export default App;

 

저는 현재 프로젝트에서 emotion을 자주 사용 중인데, emotion을 쓰는 경우

 

상속받을 부모를 React.ButtonHTMLAttributes<HTMLButtonElement> 대신,

 

DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement> 로 바꿔주시면 됩니다.

 

import { ButtonHTMLAttributes, DetailedHTMLProps } from "react";
import * as Style from "./style";

export interface ButtonProps
  extends DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement> {
  width: number;
}

const Button = (props: ButtonProps) => {
  return <Style.Button {...props} />;
};

export default Button;

 

import styled from "@emotion/styled";
import { ButtonProps } from "components/common/Button";

export const Button = styled.button<ButtonProps>`
  width: ${({ width }) => `${width}rem`};
`;

 

import Button from "components/Button";

const App = () => {
  return (
    <Button width={100} onClick={() => console.log("Button Clicked")}>
      Button
    </Button>
  );
};

export default App;

 

물론, 딱 필요한 props만을 받기 위해 html 태그의 기본 props들을 상속받지 말아야 할 경우도 있겠지만,

 

Button, Input과 같이 간단한 컴포넌트의 경우 일일이 interface와 type을 작성하는 시간을 줄여주고, 확장성이 좋아

 

컴포넌트 유지 보수에 리소스가 줄어들었습니다.

댓글