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

2023年10月18日React

Reactで配列の中のオブジェクトのプロパティすべてをpropsとして渡す方法を紹介します。
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}です。
分割代入することで、すべてのオブジェクトの値を渡すことができます。
分割代入はとても便利なのですが、万能選手というわけではなく、使わない方がいいケースもあります。
たとえばコードの安全性や可読性を高めたい場合は、実際に使用するプロパティ(id, img, title, price, amount)のみを明示的に渡すほうがいい場合があります。
なぜならコンポーネントに不要なデータが渡されるのを防ぎ、プロパティの意図を明確にでき、不要な再レンダリングを防ぎやすいというメリットがあるからです。
ケースバイケースで使えるときには分割代入を取り入れましょう。

分割代入ですべての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.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未使用の場合)。

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

React

Posted by devsakaso