REACT
cloneElement
gurwhddl
2023. 7. 25. 15:00
cloneElement란
[https://react.dev/reference/react/cloneElement]
리액트 최상위 API로 말 그대로 Element를 복제(clone)해서 반환해주는 역할을 함
리액트로 sns 사이트를 만들고 있는데 form을 사용해야 하는 경우가 매우 많음
ex)회원가입 , 로그인 , 프로필 변경 등등...
각 form에서 수집하는 데이터 또한 다르고, form 끼리 중복되지 않는 경우도 있음
- 회원가입의 경우 아이디,비밀번호,닉네임,폰번호,집주소....
- 프로필 변경의 경우에는 프로필사진,닉네임...
그래서 일단 Form과 Input 컴포넌트를 만들어놓고, 필요한 페이지에 따라 Input을 추가하려고 했는데
react-hooks-form을 사용하고 있었기 때문에, Form 컴포넌트에서 생성한 register라는 함수를 자식인 Input에 전달해줘야 했는데
그냥 {children}을 쓰게 되면 Input 컴포넌트는 렌더링 되겠지만, register라는 함수를 전달해줄 수가 없음
<form
onSubmit={handleSubmit((data) => {
submitEventHandler(data);
})}>
{Children.map(children, (child) =>
cloneElement(child, {
htmlFor: child.props.type,
register: checkType(register, child.props.type),
error: errors[child.props.type],
})
)}
<Button type="submit">제출</Button>
</form>
요약하자면 자식으로 오는 컴포넌트에 특정 props를 전달해서 쓰고 싶다는 소리
부모 컴포넌트에서 자식 컴포넌트에 props를 '동적'으로 넣어야 할 때 사용하면 좋음
Input 컴포넌트의 props를 해당 Input의 기존 props 값에 따라 동적으로 할당해줄 수 있음
자식 컴포넌트가 여러개 일때 Children.map을 사용하지 않으면 오류 발생
또 다른 방법
공식 문서에서
Using cloneElement is uncommon and can lead to fragile code 라고 소개하면서 제공한 대안은
export default function List({ items, renderItem }) {
const \[selectedIndex, setSelectedIndex\] = useState(0);
return (
{items.map((item, index) => {
const isHighlighted = index === selectedIndex;
return renderItem(item, isHighlighted);
})}
<List
items={products}
renderItem={(product, isHighlighted) =>
<Component props...>
}
/>
- cloneElement에서는 추가하고 싶은 컴포넌트를 자식 태그에 추가했다면, 이 방법은 props를 통해서 전달
- items에는 전달하고 싶은 props의 데이터를 , renderItem은 컴포넌트와 props를 지정해놓고 map을 통해서 return