ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [React] cloneElement
    Front-End(Web)/React - 프레임워크(React, Next) 2023. 3. 22. 03:15
    반응형

    React로 개발하면서, 공통 UI 혹은 기능을 가진 랩핑 컴포넌트를 만드는 경우가 종종 있다.

    type Props = ButtonHTMLAttributes<HTMLButtonElement>;
    
    function AddTravelerButton({ children, ...props }: PropsWithChildren<Props>): JSX.Element {
      return (
        <Button {...props}>
          <Text>{children}</Text>
        </Button>
      );
    }

     

    이 랩핑 컴포넌트에서 Props로 받은 값으로 특정 속성을 만든다고 가정하자.

    해당 컴포넌트에서 이 속성값을 사용하는 건 쉽지만, 내부의 {children} 에 이 속성값을 전달할 방법이 전혀 떠오르지 않았다.

     

    이를 구현하기 위해 리서치해본 결과, cloneElement라는 React의 기능을 활용하면 되었다.

     


    💙 cloneElement

    const clonedElement = cloneElement(element, props, ...children)

    React에서 엘리먼트를 조작하기 위해 제공되는 API 중 하나이다.

    특정 엘리먼트에 새로운 설정을 추가한 새 엘리먼트를 복제 및 반환을 해준다. 인자는 아래 3개를 받는다.

    • element : 복제할 원본 엘리먼트
    • props : 원본 엘리먼트에 추가할 props(객체 형태로 전달). 기존 props에 추가된 값들을 오버라이딩한다.
    • [...children] : 복제된 객체의 children

     

    cloneElement를 통해 같은 베이스의 일부 기능만 다른 코드들이 양산되는 것을 지양하고, 효율적으로 이를 확장할 수 있다.

    공식문서도, children 엘리먼트의 props 추가/수정을 통한 컴포넌트 기능 확장이 가능하다고 언급한다.

     

     

    - 샘플코드

    const Parent = ({ children, one }) => {
      const two = one + 1;
    
      return <>{React.cloneElement(children, { two: two })}</>;
    };
    
    const Child = ({ two }) => <div>one + one = {two}</div>;
    
    const App = () => (
      <Parent one={1}>
        <Child />
      </Parent>
    );

    부모 컴포넌트cloneElement를 반환하면 된다. 첫 번째 인자로 children, 두 번째 인자로 추가할 props를 제공한다.

    자식 컴포넌트는 별도의 전달 없이도, cloneElement를 통해 전달한 props들을 받을 수 있다.

     

    이처럼, 부모 컴포넌트에서 생성 혹은 계산된 값을 자식 컴포넌트(children)에게도 전달하기 위해 많이 사용된다.

     

     

    - Pitfall(잠재위험)?

    공식문서에서 볼 수 있듯, cloneElement를 레거시이자 pitfall한 기능으로 안내하고 있다.(props 추가/수정 트래킹이 힘듬)

    그 대안으로, render props 패턴을 권장하고 있다.

    const Parent = ({ render }) => {
      const newProp = 'some new prop';
    
      return render(newProp);
    }
    
    const Child = ({ newProp }) => <div>{newProp}</div>;
    
    const App = () => (
      <Parent render={props => <Child newProp={props} />} />
    );

    이 형태로도 충분히 구현은 가능하며, 단 차이점은 cloneElement는 기존 자식 컴포넌트의 key, ref를 유지해준다는 것이다.

    위를 착안해서, 상황에 맞게 적절한 패턴을 사용하면 될 것 같다!

     


     

    📎 출처

    - [cloneElement] React 공식문서(신) : https://react.dev/reference/react/cloneElement  

     

    - [cloneElement 사용예시] heyoki! 님의 블로그 : https://itchallenger.tistory.com/711

    - [cloneElement 사용예시] 수박수 님의 블로그 : https://watermelonlike.tistory.com/entry/React-Clone-element

    반응형
Designed by Tistory.