세 가지 타입은 아래와 같이 포괄 관계를 가진다:
ReactNode > ReactElement ≒ JSX.Element
ReactNode: 가장 포괄적인 타입. 문자열, 숫자, boolean, null, undefined, ReactElement, ReactFragment, ReactPortal 등 모두 포함된다.ReactElement: 컴포넌트의 반환값으로 가장 많이 사용되는 타입. JSX의 결과물이기도 하다.JSX.Element: ReactElement<any, any>의 타입 alias로 거의 같은 개념이다.ReactElement는 컴포넌트가 반환하는 객체의 형태를 타입으로 정의한 것이다.
interface ReactElement<P = any, T extends string | JSXElementConstructor<any> = string | JSXElementConstructor<any>> {
type: T;
props: P;
key: Key | null;
}
즉, JSX 문법을 사용하면 내부적으로 React.createElement() 함수가 호출되어 ReactElement 객체를 생성한다.
예를 들어 다음 JSX 코드를:
<CustomButton disabled>버튼</CustomButton>
바벨은 아래처럼 트랜스파일링 한다:
React.createElement(CustomButton, { disabled: true }, "버튼")
JSX.Element는 전역 JSX 네임스페이스에 정의되어 있으며, React.ReactElement<any, any>와 같다.
declare global {
namespace JSX {
interface Element extends React.ReactElement<any, any> {}
}
}
따라서 함수형 컴포넌트에서 반환하는 타입으로 JSX.Element 또는 ReactElement를 사용할 수 있다. 사실상 이 둘은 동일하다고 봐도 무방하다.
function MyComponent(): JSX.Element {
return <div>Hello</div>;
}
ReactNode는 JSX에서 표현할 수 있는 모든 값을 포함하는 타입이다. 대표적으로 다음과 같은 타입들이 포함된다:
string, numberboolean (렌더링되지 않음)null, undefinedReactElementReactFragment (여러 요소를 묶는 용도)ReactPortal (DOM 외부로 렌더링)예를 들어 children 타입에 가장 흔하게 사용되는 타입이다:
type PropsWithChildren<P> = P & { children?: ReactNode };
function Layout({ children }: { children: ReactNode }) {
return <div>{children}</div>;
}
| 상황 | 타입 추천 | 이유 |
|---|---|---|
| 함수형 컴포넌트 반환값 | ReactElement or JSX.Element | 대부분 JSX를 반환하므로 |
| children prop | ReactNode | 텍스트, 태그, 배열 등 모든 표현 가능 |
| UI를 동적으로 조립할 때 | ReactNode | 배열, 조건부 렌더링 등을 지원해야 함 |
| 특정 엘리먼트를 명확히 감쌀 때 | ReactElement | React.cloneElement() 등과 같이 엘리먼트 자체를 다룰 때 |