Render Delegation

ref- https://kciter.so/posts/render-delegation-react-component/#user-content-fn-1

예시

<Label.Root>
	라벨
</Loble.Root>
<Label.Root asChild>
	<a ref='something'>라벨</a>
</Label.Root>

내부 구현 : Slot & Slottable

Slottable 컴포넌트


const Slottable = ({children}) => {
	return <>{children}</>
}

Slot 컴포넌트


conset Slot = ({children, ...props}) => {
	const childrenArray = React.children.toArray(children);
	const slottable = childrenArray.find((child)=> {
		return React.isValidElement(child) & child.type === Slottable;
	})

	if(slottable){
	    // slottable 이 있다면, slottable 의 자식을 새로운 요소(newElement)로 사용
		const newElement = slottable.props.children;
		// 새로운 자식 요소 생성
		const newChildren = childrenArray.map((child)=> {
			 // Slottable 이 아니라면 그대로 반환하고
			if(child !== slottable) return child;
			// Slottable 이라면 해당 영역을 자식 컴포넌트의 children 으로 교체한다.
			if(React.isValidElement(newElement)){
				return newElement.props.children;
			} 
	
		})
	
	    if(React.isValidElement(newElement)){
		    return React.cloneElement(
			    newElement,
			    {...props, ...newElement.props},
			    newChildren
		    ) 
	    }
	    return null;
	
	}

	if(React.isValidElement(children)){
		return React.cloneElement(children, {
			...props,
			...children.props,
		})
	}
	return null;
}

실제로 컴포넌트에 적용한다면 아래와 같이 된다.

// Button 컴포넌트
const Button = ({ children, ...props }) => {
  return (
    <Slot {...props}>
      <button className="ds-button">
        <Slottable>{children}</Slottable>
      </button>
    </Slot>
  );
};

// 사용 예시
<Button asChild>
  <a href="/some-link">Click me</a>
</Button>

언제쓸 수 있을까?