🦴

REACTでProps受け渡しの実装

に公開

はじめに

親コンポーネントから子コンポーネントへのpropsの受け渡しの実装方法を定型化しておく。
ここでは、トップページ(親コンポーネント)に配置するボタン(子コンポーネント)を呼び出すユースケースとするが、基本的にどのユースケースでも実装は同じ。

定型化について

TERMS

TERMS DESCRIPTION
Props コンポーネント間で渡す引数のようなもの。親コンポーネントの関数の引数としてPropsを指定し、子コンポーネントへオブジェクトとして渡す。
コンポーネント 画面要素の1単位。REACTは各コンポーネントを利用し、組み合わせて、WEBページを作成する。粒度は様々であるが、再レンダリングの範囲を制限するための設計が必要になる。Atomic Designの考え方を踏襲するのであれば、最小単位はAtoms(ボタン、テキストボックス等)になる。最終的にページ出力する場合は、親コンポーネントで、作成した各コンポーネントをImportして表示する。コンポーネント化された各要素の集合が画面を構成する。
レンダリング WEB画面への描写を行うこと。DOM変更部分を読み込み、再表示を行う。再レンダリングが多く発生することで、WEBレスポンスのパフォーマンスに影響する為、適切な大きさのコンポーネント粒度、および再レンダリング対応が必要となる。

コンポーネントは基本memo化する

  • Propsが変更されたコンポーネントは再レンダリングされる、また、再レンダリングされたコンポーネント配下の子要素も合わせて再レンダリングされる。このため、親コンポーネントでPropsが変更されると、配下すべての子コンポーネントにレンダリングがかかることになる。多くのコンポーネントにレンダリングが発生すると多くの処理が発生し、レスポンス低下等が発生する可能性がある。
  • よって負荷軽減が必要となる。子コンポーネント側で、memo機能を利用し、親コンポーネントが再レンダリングされても、子コンポーネントは再レンダリングが発生しないようにする。呼び出される子コンポーネントは基本memo化しておく。
export const PrimaryButton: FC<Props> = memo((Props) => {
    const { children, onClick } = Props;
    return <SButton onClick={onClick}>{children}</SButton>;
});

受け渡すPropsの型を定義する

  • 型安全性の向上: Propsの型を定義することにより、TypeScriptの静的型チェッカーがコードを解析し、型エラーを事前に検出できる。
  • ドキュメンテーション提供: Propsの型定義は、コンポーネントがどのようなPropsを受け取り、それらのPropsの目的や制約をドキュメント化する際に役立つ。他の開発者がコンポーネントを理解し、適切に使用できる。
  • コード可読性の向上: コンポーネントのPropsが型定義されているため、開発者はどのPropsが必須であるか、どのPropsがオプションであるかを把握できる。
type Props = {
    children: ReactNode;
    onClick: () => void;
}

上記は、ReactNode型を利用してコンポーネント間でPropsを渡している。ReactNode型は、Reactコンポーネントが受け入れることができるほぼすべての要素やコンポーネントを表す。これにより、異なる種類の子要素(テキスト、コンポーネント、HTML要素等)をまとめて渡す際に非常に柔軟に扱うことができるメリットがある。

一方で、型安全性が低下する可能性がある。型チェッカーは、Propsの型がReactNodeの場合、子要素の型に関してほとんど制約を課さない。そのため、誤った型の子要素を渡してもコンパイルエラーが発生しないケースがあることに留意する。

親コンポーネントから呼び出す

  • 親コンポーネントから子コンポーネントを呼び出す。ボタンのAtomコンポーネントを設置する場合は、children, onClickがないとエラーとなる。要素の無いボタン、およびonClickが定義されてないと受け入れられないようにできる。
export const Home: FC = memo(() => {
    const [count, setCount] = useState(0);
    const onClickCountUp = useCallback(() => setCount(count + 1), [
        count,
        setCount
    ]);
    
    return (
        <>
            <p>This is count up test page.</p>
            <p>{count}</p>
            <PrimaryButton onClick={onClickCountUp}><div>Count Up</div></PrimaryButton>
        </>
    );
});

ソースコード

  • 親コンポーネント
import { FC, memo, useCallback, useState } from "react";
import { PrimaryButton } from "../atoms/button/PrimaryButton";

export const Home: FC = memo(() => {
    const [count, setCount] = useState(0);
    const onClickCountUp = useCallback(() => setCount(count + 1), [
        count,
        setCount
    ]);

    return (
        <>
            <p>This is count up test page.</p>
            <p>{count}</p>
            <PrimaryButton onClick={onClickCountUp}><div>Count Up</div></PrimaryButton>
        </>
    );
});
  • 子コンポーネント
import { FC, memo, ReactNode} from "react";
import styled from "styled-components";

const SButton = styled.button`
    color: #FFFFFF;
    background-color: #CC6633;
    padding: 8px 40px;
    border: none;
    border-radius: 1000px;
    outline: none;
    &:hover {
        cursor: pointer;
        opacity: 0.7;
    }
`;

type Props = {
    children: ReactNode;
    onClick: () => void;
}

export const PrimaryButton: FC<Props> = memo((Props) => {
    const { children, onClick } = Props;
    return <SButton onClick={onClick}>{children}</SButton>;
});

REACTコンポーネントの型

export const PrimaryButton: FC<Props> = memo((Props) => {
    const { children, onClick } = Props;
    return <SButton onClick={onClick}>{children}</SButton>;
});

上記は、子コンポーネントであるREACTコンポーネントである。FCは、Reactコンポーネントの型を指定するためのTypeScriptの型エイリアスである。FCは「Functional Component」の略で、関数コンポーネントを表す型のことである。FC型定義は以下の通り。

type FC<P = {}> = FunctionComponent<P>;

PはPropsの型を指定する型引数。デフォルトは空のオブジェクト{}が指定されているが、これはPropsを持たない場合に使用される。FCはPropsの型を指定するための型エイリアスであり、関数コンポーネントのPropsの型を指定するために使用する。

Discussion