HTMLElement를 컴포넌트 Props로 넘겨주기(Typescript, React)

최석훈·2022년 8월 22일
0

HTEMLElement를 컴포넌트의 props로 넘겨줄 일이 생겼다. 그 이유는 웹에 일정한 틀에 컴포넌트들을 담아주고 싶었기 때문이다. 내가 만들고 있어 웹페이지는 간단한 todolist라서 큰 웹 전체를 사용할 필요가 없어서 모든 페이지에서 공용으로 사용할 프레임 컴포넌트가 필요했다.프레임 컴포넌트를 제작할 때는 모든 페이지에서 사용해야하므로 재사용성을 잘 생각해서 짜야한다.

interface IBaseFrame {
  children: React.ReactNode;
}

const BaseFrame: React.FC<IBaseFrame> = ({ children }) => {
  return <div className={styles.container}>{children}</div>;
};

const ToDoList = () => {
  return (
    <BaseFrame>
       <CheckboxList/>
       <ToDoInput/>
    </BaseFrame>
  );
};

ToDoList 컴포넌트를 보면 BaseFrame안에 CheckboxList와 ToDoInput이 들어있는데 이렇게 작성을 하면 BaseFrame의 children prop으로 자동넘어가게 된다.

그리고 BaseFrame 컴포넌트는 children을 항상 받아야하므로 Interface로 props type을 정해줬다. children의 타입은 React.ReactNode이다.

컴포넌트 타입으로 올 수 있는 타입들은 JSX.Element, ReactElement, ReactNode 이렇게 세개가 있는데 클래스형 컴포넌트는 render 메소드에서 ReactNode를 리턴하고 함수형 컴포넌트는 ReactElement를 리턴한다.
바벨에 의해서 JSX는 React.createElement로 변환이 된다.
React.createElement의 리턴 타입이 ReactElement, JSX.Element이다.

interface ReactElement<P = any, T extends string | JSXElementConstructor<any> = string | JSXElementConstructor<any>> {
        type: T;
        props: P;
        key: Key | null;
    }
    
type ReactNode = ReactElement | string | number | ReactFragment | ReactPortal | boolean | null | undefined;

declare global {
    namespace JSX {
        interface Element extends React.ReactElement<any, any> { }
        interface ElementClass extends React.Component<any> {
            render(): React.ReactNode;
        }
        ...

타입을 분석을 해보면 JSX.Element는 React.Element를 상속받고 ReactNode는 ReactElement이외에도 null등 다른 타입을 가질 수 있다.
따라서 ReactNode <= ReactElement <= JSX.Element 이와 같은 관계를 가진다는 것을 알 수 있다.

그렇다면 왜 children 타입으로 ReactNode를 사용했나?
그 이유는 ReactElement는 null, undefined가 될 수 없기 때문이다. 프레임으로 사용하는 컴포넌트이긴 하지만 자식으로 아무것도 안들어올 수 있는 경우도 있을 것이기 때문에 null, undefined가 될 수 있는 ReactNode로 타입을 지정했다.

배운점
항상 컴포넌트 타입을 지정할 때 어떤 타입을 써야할지 헷갈렸는데 직접 타입 내부 코드를 들여다 봄으로써 근본(?)부터 공부할 수 있어서 재밌었다. 제대로 집고 넘어갈 수 있어서 속이 시원했다.

참고
https://ko.reactjs.org/docs/composition-vs-inheritance.html
https://simsimjae.tistory.com/426

profile
하루를 열심히

0개의 댓글