본문 바로가기

React/실험실

[React] Polymorphic 한 컴포넌트

What are Polymorphic Components ?

React를 공부할 때 가장 먼저 배우는 개념 중 하나는 재사용 가능한 컴포넌트를 만드는 것이다. 

컴포넌트를 한 번 작성하고 여러번 재사용하는 기술이다. 

 

고전적인 재사용 가능한 컴포넌트의 필수 구성요소는 Props와 State이며, Props는 외부에 있으며, 

State는 내부에 존재한다. 

재사용성의 필수 구성요소인 Props와 State는 Polymorphic Components에서도 여전히 유효하지만 

최종적으로 렌더링할 요소를 결정할 수 있도록 element를 활용할 것이다.

 

const MyComponent = (props) => {
  return (
    <div>
     This is an excellent component with props {JSON.stringify(props)}
   </div>
  );
};

 MyComponent는 항상 div를 렌더링하고 있다. 

하지만 컴포넌트가 컴포넌트 내에서 사용할 데이터인 {JSON.stringify(props)} 이상을 제공한다면 어떨까? 

 

즉, div만 렌더링하는 것이 아닌 props를 통해서 렌더링할 DOM을 결정할 수 있다면? 

Polymorphic Components의 역할이 바로 이것이다. 

 

Polymorphic 이란 여러 가지 형태로 존재한다는 뜻이다. 

React의 컴포넌트 세계에선 다른 컨테이너 엘리먼트나 노드로 렌더링 할 수 있는 컴포넌트라는 뜻이다. 

 

Polymorphic Components의 예시

오픈 소스 컴포넌트 라이브러리는 일반적으로 Polymorphic Component를 구현하고 있다. 

 

Chakra UI는 다크 테마나 애니메이션 등을 제공하는 컴포넌트이다. 

여기서 Chakra UI는 어떤 방법으로 Polymorphic props를 사용하고 있을까? 

 

정답은 as props이다. 

 

as props는 컴포넌트에 전달되어 렌더링할 최종 컨테이너 요소를 결정합니다.

 

즉, as에 따라서 컴포넌트가 변경된다고 볼 수 있다. 

 

간단한 Polymorphic Component 만들기

생각보다 Polymorphic Component는 만들기 쉽다. 

const MyComponent = ({ as, children }) => {
  const Component = as || "span";

  return <Component>{children}</Component>;
};

사용되는 방식은 Chakra UI의 Props와 동일하다. 

as를 사용해서 렌더링 요소를 제어할 수 있다. 

 

이때 주의할 점이 있는데, as를 바로 렌더링을 하면 안된다. 

const MyComponent = ({ as, children }) => {
  // wrong render below 👇 
  return <as>{children}</as>;
};

런타임에 Element를 렌더링할 때는 대문자로 된 변수에 할당하고 대문자로 된 변수를 렌더링해야 한다. 

이제 다음과 같이 컴포넌트를 사용할 수 있다. 

<MyComponent as="button">Hello Polymorphic!<MyComponent>
<MyComponent as="div">Hello Polymorphic!</MyComponent>
<MyComponent as="span">Hello Polymorphic!</MyComponent>
<MyComponent as="em">Hello Polymorphic!</MyComponent>

생각해봐야 할 사항

다음과 같은 방법은 몇가지 단점을 가지고 있다. 

1. 잘못된 HTML 요소를 as prop가 전달받을 수 있다. 

<MyComponent as="emmanuel">Hello Wrong Element</MyComponent>

as props로 emmanuel을 전달하고 있다. 

emmanuel은 실제로 존재하지 않는 HTML 요소이지만 브라우저는 이 요소도 렌더링하려고 시도한다. 

이상적인 개발 환경은 개발 중 어떤 종류의 오류가 발생했을 때 이를 표시하는 것이다. 

예를 들어, 사용자가 div 대신 divv라는 간단한 오타를 입력해도 무엇이 잘못되었는지 표시되어야 한다. 

 

2. 유효한 요소에게 잘못된 속성이 전달될 수 있다.

<MyComponent as="span" href="https://www.google.com">
   Hello Wrong Attribute
</MyComponent>

사용자는 as prop로 span을 전달할 수 있고, href prop 역시 전달할 수 있다. 

 

하지만 기술적으로는 유효하지 않는 방법이다. 

span 요소는 href 속성을 포함하지 않으며, 포함해서는 안된다. 이것은 잘못된 HTML 구문이다. 

 

그러나 우리가 만든 컴포넌트는 이러한 코드를 작성하더라도 오류가 발생하지 않는다. 

 

3. Attribute를 지원하지 않는다. 

const MyComponent = ({ as, children }) => {
  const Component = as || "span";

  return <Component>{children}</Component>;
};

MyComponent가 허용하는 props는 as와 children 뿐이다. 

유효한 as에 대한 attribute를 지원하지 않고 있다. 

 

즉, as가 a 라면 컴포넌트에서는 href를 전달하는 것도 지원해야 한다. 

<MyComponent as="a" href="...">A link </MyComponent>

위 예시에서는 href를 전달하고는 있지만 컴포넌트에서 as와 children을 제외한 다른 props는 받지 않는다. 

컴포넌트에 전달된 다른 모든 props를 다음과 같이 작성할 수 있다. 

const MyComponent = ({ as, children, ...rest }) => {
  const Component = as || "span";

  return <Component {...rest}>{children}</Component>;
};

 

이것은 괜찮은 해결책이 될 수 있지만, 위에서 언급한 두 번째 문제가 아직 해결되지 않았다. 

잘못된 속성은 여전히 컴포넌트에도 전달되고 있다. 

<MyComponent as="span" href="https://www.google.com">
   Hello Wrong Attribute
</MyComponent>

 

 

참고

https://www.freecodecamp.org/news/build-strongly-typed-polymorphic-components-with-react-and-typescript/#github-repository

 

Intermediate TypeScript and React Handbook – How to Build Strongly Typed Polymorphic Components

Hey everyone! 😎 In this detailed guide, I’ll show you how to build strongly typed Polymorphic React components with Typescript. If you prefer to read the entire guide in a single PDF document, you can download the accompanying free PDF [https://www.oh

www.freecodecamp.org

 

반응형

'React > 실험실' 카테고리의 다른 글

[React] MSW 잘 사용해보기  (0) 2023.06.08
[React] Cookie  (1) 2023.06.01
[React] useMemo를 사용하지 말아야 한다!  (0) 2023.04.20
[React] React18에서 추가된 Hook  (0) 2023.04.17
[React] useState vs useReducer  (0) 2023.04.16