cloneElementを使用して親要素から小要素へpropsを渡す方法

Reactプロジェクトにおいてchildrenに対してpropsを渡したい場合がある。
そのような場合は以下のように書けば値を引き渡すことが可能になる。
以下はプロフィール情報を表示するためのソースになる。

interface CommonProps {
    mainTitle: string;
}

interface ChildProps {
    name: string;
    age: number;
    gender: "Men" | "Female";
}

const RenderChild: React.FC<ChildProps> = (props: ChildProps & CommonProps): JSX.Element => {
    const { mainTitle, name, age, gender } = props;
    return (
        <div>
            <h1>{mainTitle}</h1>
            <p>{name}</p>
            <p>{age}</p>
            <p>{gender}</p>
        </div>
    );
};

interface ParentProps extends CommonProps {
    children: React.ReactElement<ChildProps>[];
}

const RenderParent: React.FC<ParentProps> = (props: ParentProps): JSX.Element => {
    const { children, ...newProps } = props;
    const childrenWithProps = React.Children.map(children, (child: React.ReactElement) => React.cloneElement(child, { ...newProps }));
    return <div>{childrenWithProps}</div>;
};

実行

<RenderParent mainTitle="Profile">
    <RenderChild name={"foo"} age={22} gender="Men" />
    <RenderChild name={"bar"} age={23} gender="Female" />
    <RenderChild name={"hoge"} age={22} gender="Men" />
</RenderParent>

肝心なポイントはRenderParentコンポーネントになる
これは渡ってきたchildren(JSXElement)をコンポーネント内でcloneさせている

React.Children.map(children, (child: React.ReactElement) => React.cloneElement(child, { ...newProps }));

childrenをmapでループさせ、中にあるchild一つ一つにpropsを渡して新しくJSXElementを生成させている
そうして新しく出来たchildrenWithPropsをRenderParentで返すという手法
これで子コンポーネントであるRenderChildのpropsにはChildPropsCommonPropsが入ってくるようになる。

関連記事