React

【React】配列の中のオブジェクトのプロパティすべてをpropsとして渡す方法

Reactで配列の中のオブジェクトのプロパティすべてをpropsとして渡す方法を紹介します。 TypeScriptの使用した場合の書き方、React.memoを使って再レンダリングを防ぐ方法、PropTypesを使う方法、静的データの場合のuseMemo活用なども合わせて紹介します。

この記事の目次
  1. Reactで配列の中のオブジェクトのプロパティすべてをpropsとして渡す方法
  2. 分割代入ですべてpropsとして渡す
  3. 分割代入ですべてのpropsを受け取る
  4. 型安全性を強化(TypeScriptの使用)
  5. パフォーマンス最適化:React.memoの利用
  6. PropTypesを使う方法
  7. 静的データの場合のuseMemo活用

Reactで配列の中のオブジェクトのプロパティすべてをpropsとして渡す方法を紹介します。
結論は<CartItem key={item.id} {...item} />です。JSXの中でオブジェクトに...を付けると(スプレッド構文)、オブジェクトのプロパティ1つ1つが同名のpropsとして渡されます。受け取る側は引数で({ id, title, price })のように分割代入すれば、必要なものだけ取り出せます。
TypeScriptを使用した場合の書き方、React.memoを使って再レンダリングを防ぐ方法、PropTypesを使う方法、静的データの場合のuseMemo活用なども合わせて紹介します。

Reactで配列の中のオブジェクトのプロパティすべてをpropsとして渡す方法

以下のようなオブジェクトをもった配列を例とします。

const cartItems = [
  {
    id: 1,
    title: "タイトル1",
    price: "100",
    img: "image-path.jpg",
    amount: 1,
  },
  {
    id: 2,
    title: "タイトル2",
    price: "100",
    img: "image-path.jpg",
    amount: 1,
  },
  {
    id: 3,
    title: "タイトル3",
    price: "100",
    img: "image-path.jpg",
    amount: 1,
  },
  {
    id: 4,
    title: "タイトル4",
    price: "100",
    img: "image-path.jpg",
    amount: 1,
  },
  {
    id: 5,
    title: "タイトル5",
    price: "100",
    img: "image-path.jpg",
    amount: 1,
  },
];

これをpropsとして渡すときいちいちmapメソッドの中でtitle={item.title}などとはしていられません。

次のようにします。

スポンサーリンク

分割代入ですべてpropsとして渡す

import React from "react";
import { useSelector } from "react-redux";
import CartItem from "./CartItem";

const CartContainer = () => {
  const { cartItems, amount, total } = useSelector((state) => state.cart);
  return (
        <div>
          {cartItems.map((item) => {
            return <CartItem key={item.id} {...item} />;
          })}
        </div>
  );
};

export default CartContainer;

ポイントは{...item}です。
この...はスプレッド構文で、オブジェクトのプロパティをすべて展開して個別のpropsとして渡します。title={item.title} price={item.price}と1つずつ書いたのと同じ結果になります。見出しでは慣例的に「分割代入」と呼んでいますが、正確には渡す側がスプレッド構文、受け取る側が分割代入です。
スプレッド構文はとても便利ですが、万能ではなく、使わないほうがよいケースもあります。
コードの安全性や可読性を高めたい場合は、実際に使用するプロパティ(id, img, title, price, amount)だけを明示的に渡すほうが向いています。
コンポーネントに不要なデータが渡されるのを防ぎ、プロパティの意図を明確にでき、不要な再レンダリングを防ぎやすいからです。
この例のように「オブジェクトのキー名とpropsの名前が一致していて、その全部を使う」場面では、スプレッド構文が簡潔です。JSX内で{}に書けるものの規則はJSX内にJavaScriptの式を埋め込む方法で解説しています。

分割代入ですべてのpropsを受け取る

import React from "react";

const CartItem = ({ id, img, title, price, amount }) => {
  return (
    <article className="cart-item">
      <img src={img} alt={title} />
      <div>
        <h2>{id}: {title}</h2>
        <h4>¥{price}</h4>
      </div>
    </article>
  );
};

export default CartItem;

型安全性を強化(TypeScriptの使用)

Reactで配列のオブジェクトをpropsとして渡す場合、TypeScriptを使用して型定義を行うと、型安全性が向上します。

type CartItemProps = {
  id: number;
  img: string;
  title: string;
  price: string;
  amount: number;
};

const CartItem: React.FC<CartItemProps> = ({ id, img, title, price, amount }) => {
  return (
    <article className="cart-item">
      <img src={img} alt={title} />
      <div>
        <h2>{id}: {title}</h2>
        <h4>¥{price}</h4>
      </div>
    </article>
  );
};

型定義を行うことで、渡されるpropsの型チェックが可能になります。
開発中にプロパティのミス(タイプミスや不足)を防げます。
なおReact.FCを使わず、const CartItem = ({ id, img, title, price, amount }: CartItemProps) => { ... }と引数に直接型を付ける書き方も一般的です。どちらでも動作は変わりません。子要素を受け取るコンポーネントの型付けはpropsのchildrenの使い方を参照してください。

パフォーマンス最適化:React.memoの利用

CartItemが受け取るpropsが頻繁に変化しない場合、React.memoを使って再レンダリングを防げます。

import React, { memo } from 'react';

const CartItem = memo(({ id, img, title, price, amount }) => {
  return (
    <article className="cart-item">
      <img src={img} alt={title} />
      <div>
        <h2>{id}: {title}</h2>
        <h4>¥{price}</h4>
      </div>
    </article>
  );
});

export default CartItem;

親コンポーネント(CartContainer)が再レンダリングされても、子コンポーネント(CartItem)が無駄に再レンダリングされなくなります。
パフォーマンスの向上が期待できます。

PropTypesを使う方法

CartItemのプロパティが全て渡されることを確認するため、PropTypesを使う方法もあります(TypeScript未使用の場合)。
ただし、React 19では関数コンポーネントのpropTypesチェックが削除され、設定しても無視されます。React 18以前のプロジェクト向けの方法と考え、React 19以降で型チェックをしたい場合はTypeScriptを使ってください。

import PropTypes from 'prop-types';

const CartItem = ({ id, img, title, price, amount }) => {
  return (
    <article className="cart-item">
      <img src={img} alt={title} />
      <div>
        <h2>{id}: {title}</h2>
        <h4>¥{price}</h4>
      </div>
    </article>
  );
};

CartItem.propTypes = {
  id: PropTypes.number.isRequired,
  img: PropTypes.string.isRequired,
  title: PropTypes.string.isRequired,
  price: PropTypes.string.isRequired,
  amount: PropTypes.number.isRequired,
};

export default CartItem;

TypeScriptを使わないプロジェクトでも、最低限の型チェックを行えます。

静的データの場合のuseMemo活用

import React, { useMemo } from 'react';

const CartContainer = () => {
  const { cartItems } = useSelector((state) => state.cart);

  const memoizedCartItems = useMemo(() => {
    return cartItems.map(({ id, img, title, price, amount }) => (
      <CartItem
        key={id}
        id={id}
        img={img}
        title={title}
        price={price}
        amount={amount}
      />
    ));
  }, [cartItems]);

  return <div>{memoizedCartItems}</div>;
};

export default CartContainer;

cartItemsが変更されない限り、新しい配列を生成せずに済むため、パフォーマンスが向上します。

スポンサーリンク