컴포넌트의 props에 컴포넌트를 넘겨야 할 때, props의 이름과 컴포넌트의 타입을 선언해주어야 한다.
import { JSX, ReactElement, ReactNode, useEffect, useState } from 'react'
interface Props {
component: ReactElement
component1: JSX.Element
component2: ReactNode
}
하지만 이 컴포넌트의 타입은 `ReactElement` , `Element` , `ReactNode` 세가지가 있으며, 세가지 모두 리액트의 요소를 나타낸다.
이 타입들의 차이는 무엇이 있을 지 알아보자.
ReactElement
리액트에서는 JSX 문법으로 UI를 표현하고, 트랜스파일러는 JSX문법을 createElement 메서드를 통해 리액트 엘리먼트를 생성한다.
📌 JSX 문법
class Hello extends React.Component {
render() {
return <div>Hello {this.props.toWhat}</div>;
}
}
📌 createElement 메서드 사용
class Hello extends React.Component {
render() {
return React.createElement('div', null, `Hello ${this.props.toWhat}`);
}
}
리액트는 이렇게 만들어진 리액트 엘리먼트 객체를 읽어 가상 DOM을 구성한다.
이때 리액트 엘리먼트 객체의 타입이 ReactElement 이다.
ReactNode
ReactNode는 앞서 설명한 더 넓은 범주의 타입을 포함한다.
즉, ReactNode는 리액트의 render 함수가 반환할 수 있는 모든 형태를 담기고 있다고 생각하면 된다.
JSX.Element
JSX.Element는 ReactElement의 제네릭으로 any타입을 가지도록 확장하고 있다.
JSX.Element 는 ReactElement의 특정 타입으로 props와 타입필드를 any로 가지는 타입이라는 것만 알면 된다.
지금껏 살펴본 세가지 타입의 포함관계를 정리하면 아래의 그림과 같다.
📌 요약 정리
타입 | 설명 |
ReactElement | JSX의 createElement 메서드의 리턴타입인 엘리먼트 객체의 타입. 즉, JSX 문법을 사용하면 트랜스파일러가 createElement로 앨리먼트 객체로 트랜스파일하는데, 그 객체의 타입이다. |
ReactNode | React의 render 함수가 반환할 수 있는 모든 범주의 타입. |
JSX.Element | ReactElement의 특정 타입 |
🙌 사용예시
그렇다면 어떤 상황에서 어떤 타입을 써야 할까?
ReactNode
리액트의 render 함수가 반환할 수 있는 모든 형태를 담고 있기 때문에 리액트 컴포넌트가 가질 수 있는 모든 타입을 의미한다.
리액트의 합성을 쓰기 위해 props로 children을 많이 사용했을 텐데, 이때 children의 타입도 ReactNode이다.
리액트의 내장타입인 PropsWithChildren 타입의 children의 타입은 `ReactNode` 이다.
즉, ReactNode는 ReactNode로 선언한 프로퍼티가 리액트 컴포넌트처럼 다양한 형태를 가지고 싶게 하고 싶을 때 , 혹은 리액트에 내장된 children의 쓰임새처럼 넓게 쓰고 싶을 때 사용한다.
JSX.Element
리액트 엘리먼트를 props로 전달받아 render props패턴으로 컴포넌트를 구현할 때 사용한다.
interface Props {
icon: JSX.Element
}
const Icon = ({ icon }: Props) => {
// props로 받은 컴포넌트의 props에 접근할 수 있다.
const iconSize = icon.props.size
return <li>{icon}</li>
}
const App = () => {
return <Icon icon={<Star size={14} />} />
}
ReactElement
JSX.Element에서의 props타입을 제네릭으로 지정해줄 수 있다.
interface IconProps {
size: number
}
interface Props {
icon: ReactElement<IconProps>
}
const Icon = ({ icon }: Props) => {
const iconSize = icon.props.size
return <li>{icon}</li>
}
ReactElement를 사용하면 icon.props에 접근할 때 어떤 props가 있는지 IDE가 추론할 수 있다.
출처
우아한 타입 스크립트 with 리액트 - 우아한 테크
'🌳Frontend > react' 카테고리의 다른 글
React에서 Error boundary (에러 바운더리) 를 쓰는 이유 (0) | 2025.01.11 |
---|---|
React에서 state를 정의할 때 고려해야 할 점 (feat. SSOT) (0) | 2024.02.25 |
Next.js에서 Firebase 파이어베이스로 구글 로그인 기능 구현 (0) | 2023.10.14 |
Next.js 와 파이어베이스(Firebase) 연동하기 (0) | 2023.10.14 |
Next.js 환경에서 CSS in JS Styled-Component의 치명적인 단점 (0) | 2023.10.14 |