Post

Next.js - cloneElement를 이용해 Children에게 props를 내려주자!

📌시작하며

입사하고 오랫동안 함께 하고 있는 프로젝트가 출시를 준비하면서, 프로토타입으로 만들었던 컴포넌트를 리팩토링 할 필요성이 있었다. 최근에는 생각나면 Next.js 공식문서를 살펴보는 중인데 그때 발견한 Template.ts를 적용하면서, 전체적인 컴포넌트 위치 변경이 있었고 layout.tsx를 쓰며 children에게 Props를 내려주는건 불가능할까? 하는 답답함이 있었다.

같은 생각을 하는 사람들이 있었는지, stackOverflow에서 cloneElement라는 기능을 가지고 답변한 것이 있어, 간단하게 작성해 실험해보았는데, 실제로 props를 받아오는 것을 확인해, 문서로 정리해보고자 한다.

다만 주의할점은, React 공식문서에서도 분명 이 기능을 소개하고 있지만, 데이터에 흐름을 어렵게 하며 일반적인 방법이 아니다. 대안을 시도해보라 고 분명히 안내하고 있었고, 지금은 레거시 API로 분류되었다는 것이다. 그래서, 실제 프로젝트에서는 적용하지 않았고 , 이 포스팅은 어디까지나 참고용으로 보기로 한다.

✅cloneElement

cloneElement는 다른 요소를 시작점으로 사용해 새로운 React 요소를 만드는 기능으로 사용방식은 다음과 같다. const clonedElement = cloneElement(element, props, ...children)

특정한 React Element의 props를 재정의하려면, cloneELement에 그 재정의하려는 element와 props를 전달한다.

1
2
3
4
5
import { cloneElement } from "react"

const clonedElement = cloneElement(<Row title="Cabbage" />, {
  isHighlighted: true,
})

위의 예제에서 클론한 element는 <Row title="Cabbage" isHighlighted={true} />다음과 같은 값을 가지게 된다.

✅예제

먼저 props를 내려주고 싶은 부모 컴포넌트를 만들고, children을 cloneElement를 이용해 만들어 주었다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
"use client"
import React, { ReactNode, cloneElement, Children, ReactElement } from "react"

type ParentProps = {
  children: ReactNode
}

const Parent = ({ children }: ParentProps) => {
  return (
    <div>
      <div>부모 컴포넌트의 제목</div>
      {Children.map(children, (child) => {
        // props를 전달한다.
        return cloneElement(child as ReactElement<{ propsTest?: string }>, {
          propsTest: "props가 갑니다~",
        })
      })}
    </div>
  )
}

export default Parent

그 다음 children으로 이용될 컴포넌트를 만들어 준다. 참고로 use client를 작성하지 않으면 에러가 발생한다. 부모 컴포넌트에서 내려줄 state가 propsTest란 이름이므로, 해당 props를 받갰다고 작성했다.

1
2
3
4
5
6
7
8
9
10
11
12
"use client"
import React from "react"

const Child = ({ propsTest }: { propsTest?: string }) => {
  return (
    <div>
      <div>자식 컴포넌트에서 받은 : {propsTest}</div>
    </div>
  )
}

export default Child

최상위 에서 다음과 같이 불러주었다.

1
2
3
4
5
6
7
8
9
10
import Child from "./_components/Child"
import Parent from "./_components/Parent"

export default function Clone() {
  return (
    <Parent>
      <Child />
    </Parent>
  )
}

그러면 Child에서 정상적으로 자식 컴포넌트에서 받은 값: 추가된 값 이란 글자가 렌더링 되는 것을 확인할 수 있다.

🗂️참고 사이트

This post is licensed under CC BY 4.0 by the author.