3秒でわかる
受け取ったpropsを見た目に変換することだけを担うReactの部品。通信や状態を持たないぶん、使い回しとテストが楽になります。
もう少し詳しく
どういうものか
プレゼンテーショナルコンポーネントは、データの取得や業務上の判断を持たず、渡された値をどう表示するかだけを担当する部品です。通信もしませんし、どこから来たデータかも知りません。propsが同じなら常に同じ見た目になり、入力から出力が決まる関数のように扱えます。対になるのが、データ取得や状態管理を受け持つコンテナ側の部品です。
なぜ必要か
1つの部品が通信も状態も見た目も抱えると、別の画面で使い回せなくなります。商品一覧で作ったカードを検索結果でも使いたいのに、中でその画面専用のAPIを叩いていれば流用できません。見た目だけを切り出しておけば、データ元が変わっても部品はそのまま使えます。テストでも、propsを渡して描画結果を見るだけで済みます。サーバーを立てずに確認できるので、見た目の崩れを早い段階で捕まえられます。
具体例
// 見た目だけ 何も取りに行かない
function UserCard({ name, avatarUrl, isOnline, onSelect }) {
return (
<button className="card" onClick={onSelect}>
<img src={avatarUrl} alt="" width={40} height={40} />
<span>{name}</span>
<span className={isOnline ? "dot on" : "dot off"} />
</button>
);
}
// データを持つ側から渡す
function UserList() {
const { data } = useUsers();
return data.map((u) => (
<UserCard key={u.id} {...u} onSelect={() => open(u.id)} />
));
}つまずきやすいところ
便利だからと、この部品の中で useEffect を書いて通信を始めてしまう例が多く見られます。そうなった時点で使い回しの利点は失われます。もうひとつ、propsを増やしすぎる問題です。15個も渡すようになったら、部品の切り方そのものを見直す合図です。イベントは自分で処理せず、onSelect のように関数を受け取って呼ぶだけに留めます。
似た用語との違い
| 呼び名 | 責務 |
|---|---|
| プレゼンテーショナル | 見た目だけを組み立てる |
| コンテナ | データ取得と状態を持ち、下へ渡す |
| カスタムフック | 状態やロジックを部品から切り出したもの |
覚え方
外から来た値を絵に変えるだけの部品、と捉えます。中で何かを取りに行きたくなったら、その処理は親へ押し上げる合図です。