Dynamic Tag Name Props

리액트에서 props로 태그 변경하는 방법

상황

Vue > Dynamic Components 의 연장선으로 작성하게 되었다.

위에 내용은 뷰에서 한개의 컴포넌트로 조건에 따라 렌더링 되는 태그를 변경하고 싶었다.

이전에 리액트에서 작업할 때는 styled-components 사용을 하고 있었기 때문에 styled-components 제공하는 as 프롭을 사용해서 쉽게 렌더링 태그를 변경할 수 있었다.

하지만 styled-components 사용하지 않는다면? 어떻게 해야하나? 궁금증이 생겼다.

styled-components 사용시

아래와 같이 as 를 사용하면 된다.

// button 컴포넌트
<button 
  as={href && 'a'}
  className={ href ? 'link' : 'button'}
  {...props}
> {children} </button>

// 사용시
<Button as="a" href="/">a 태그로 렌더링</Button> 
<Button>button 태그로 렌더링</Button> 

React 사용으로만 구현하기

구글링을 했을땐 제일 많이 나오는 방법은 이 방법이였고

내가 원하는 방법은 Dynamic Tag Name Props in React (with TypeScript) 이거다.

위 방법을 참고해서 직접 테스트 해본 코드샌드박스

1. DynamicTag 컴포넌트 만들기

interface Props
  extends React.AllHTMLAttributes<any>,
    PropsWithChildren<unknown> {
  children?: React.ReactNode;
  className?: string;
  tagName?: React.ElementType<any>;
}

export const DynamicTag = ({
  children,
  tagName: Tag = "div",
  className,
  ...props
}: Props): ReactElement => {
  return (
    <Tag className={className} {...props}>
      {children}
    </Tag>
  );
};

2. DynamicTag 컴포넌트를 사용해서 Button 만들기

import { DynamicTag } from "./dynamicTag";

interface Props extends PropsWithChildren<unknown> {
  className?: string;
  href?: string | undefined;
}

export const Button = ({
  children,
  href,
  className,
  ...props
}: Props): ReactElement => {
  return (
    <DynamicTag
      tagName={href ? "a" : "button"}
      className={className}
      href={href}
      {...props}
    >
      {children}
    </DynamicTag>
  );
};

3. DynamicTag, Button 컴포넌트 사용하기

// DynamicTag 컴포넌트
<DynamicTag tagName="a" href="/">
  a 로 렌더링
</DynamicTag>
<DynamicTag tagName="p"> p 로 렌더링 </DynamicTag>
<DynamicTag> div 로 렌더링 </DynamicTag>

// Button 컴포넌트
<Button href="/">a 렌더링</Button>
<Button>button 렌더링</Button>

더 연구해 볼 것

사실 위와 같은 방법이 올바른 방법인지는 모르겠다. 참고해서 작업하긴 했지만 오류에 계속 직면했다.

예를 들면 DynamicTag 컴포넌트에서 ...props 를 전달하였음에도 href 속성값을 넣으면 ts 오류가 떴다. 다른 속성값도 마찬가지로 오류가 뜸.

React.AllHTMLAttributes 흠..

// DynamicTag 에서 Props
interface Props extends React.AllHTMLAttributes<any> {
  children?: React.ReactNode;
  className?: string;
  tagName?: React.ElementType<any>;
}

// 사용시
<DynamicTag tagName="a" href="/">
  a 로 렌더링
</DynamicTag>

참고

Last updated