React PropType Array with Shape とは?

2024-04-02

React PropType Array with Shape

特に、配列型のプロパティで、各要素が特定の形状(shape)を持つ必要がある場合、React.PropTypes.shapeを使うことで、より詳細な型チェックを行うことができます。

下記は、itemsというプロパティが、nameageというプロパティを持つオブジェクトの配列であることを検証する例です。

import React from 'react';
import PropTypes from 'prop-types';

const MyComponent = ({ items }) => {
  // ...

  return (
    <div>
      {items.map((item) => (
        <div key={item.name}>
          <h1>{item.name}</h1>
          <p>{item.age}</p>
        </div>
      ))}
    </div>
  );
};

MyComponent.propTypes = {
  items: PropTypes.arrayOf(
    PropTypes.shape({
      name: PropTypes.string.isRequired,
      age: PropTypes.number.isRequired,
    })
  ).isRequired,
};

export default MyComponent;

上記のコードでは、MyComponentコンポーネントのitemsプロパティに対して、以下の検証が行われます。

  • itemsは配列であること
  • 配列の各要素はオブジェクトであること
  • オブジェクトにはnameageというプロパティが存在すること
  • nameプロパティは文字列であること

詳細

React.PropTypes.shapeは、オブジェクトの形状を検証する際に非常に便利です。

以下の例では、addressプロパティが、streetcityというプロパティを持つオブジェクトであることを検証しています。

const MyComponent = ({ items }) => {
  // ...

  return (
    <div>
      {items.map((item) => (
        <div key={item.name}>
          <h1>{item.name}</h1>
          <p>{item.address.street}</p>
          <p>{item.address.city}</p>
        </div>
      ))}
    </div>
  );
};

MyComponent.propTypes = {
  items: PropTypes.arrayOf(
    PropTypes.shape({
      name: PropTypes.string.isRequired,
      age: PropTypes.number.isRequired,
      address: PropTypes.shape({
        street: PropTypes.string.isRequired,
        city: PropTypes.string.isRequired,
      }),
    })
  ).isRequired,
};

このように、React.PropTypes.shapeを使って、複雑な形状のオブジェクトも簡単に検証することができます。

  • React.PropTypes.oneOfを使って、許可される値のリストを指定することができます。

React.PropTypes.shapeを使うことで、Reactコンポーネント間でデータを渡す際の型チェックをより詳細に行うことができます。

これは、コードの品質と信頼性を向上させるのに役立ちます。




import React from 'react';
import PropTypes from 'prop-types';

const MyComponent = ({ items }) => {
  // ...

  return (
    <div>
      {items.map((item) => (
        <div key={item.name}>
          <h1>{item.name}</h1>
          <p>{item.age}</p>
        </div>
      ))}
    </div>
  );
};

MyComponent.propTypes = {
  items: PropTypes.arrayOf(
    PropTypes.shape({
      name: PropTypes.string.isRequired,
      age: PropTypes.number.isRequired,
    })
  ).isRequired,
};

export default MyComponent;

詳細

const MyComponent = ({ items }) => {
  // ...

  return (
    <div>
      {items.map((item) => (
        <div key={item.name}>
          <h1>{item.name}</h1>
          <p>{item.address.street}</p>
          <p>{item.address.city}</p>
        </div>
      ))}
    </div>
  );
};

MyComponent.propTypes = {
  items: PropTypes.arrayOf(
    PropTypes.shape({
      name: PropTypes.string.isRequired,
      age: PropTypes.number.isRequired,
      address: PropTypes.shape({
        street: PropTypes.string.isRequired,
        city: PropTypes.string.isRequired,
      }),
    })
  ).isRequired,
};

詳細は、React PropType API リファレンス: https://www.weblio.jp/content/%E5%89%8A%E9%99%A4




React.PropTypes.shape の代替方法

  • 冗長になりやすい
  • 型定義ファイル (TypeScript など) を使用している場合は、重複が発生する

これらの欠点を克服するために、React.PropTypes.shape の代わりに以下の方法を使用することができます。

TypeScript を使用している場合は、インターフェースを使用してオブジェクトの形状を定義することができます。

interface Item {
  name: string;
  age: number;
}

const MyComponent: React.FC<{ items: Item[] }> = ({ items }) => {
  // ...

  return (
    <div>
      {items.map((item) => (
        <div key={item.name}>
          <h1>{item.name}</h1>
          <p>{item.age}</p>
        </div>
      ))}
    </div>
  );
};

この方法を使用すると、React.PropTypes.shape を使用する場合よりも簡潔で読みやすいコードになります。

zod ライブラリ

zod は、オブジェクトのバリデーションを行うライブラリです。

import zod from 'zod';

const itemSchema = zod.object({
  name: zod.string(),
  age: zod.number(),
});

const MyComponent = ({ items }) => {
  // ...

  return (
    <div>
      {items.map((item) => {
        itemSchema.parse(item); // バリデーション

        // ...

        return (
          <div key={item.name}>
            <h1>{item.name}</h1>
            <p>{item.age}</p>
          </div>
        );
      })}
    </div>
  );
};

この方法を使用すると、React.PropTypes.shape よりも詳細なバリデーションを行うことができます。

自作のバリデーション関数

上記のいずれの方法も使用できない場合は、自作のバリデーション関数を作成することができます。

function validateItem(item) {
  if (typeof item.name !== 'string') {
    throw new Error('Invalid name');
  }

  if (typeof item.age !== 'number') {
    throw new Error('Invalid age');
  }

  // ...
}

const MyComponent = ({ items }) => {
  // ...

  return (
    <div>
      {items.map((item) => {
        validateItem(item); // バリデーション

        // ...

        return (
          <div key={item.name}>
            <h1>{item.name}</h1>
            <p>{item.age}</p>
          </div>
        );
      })}
    </div>
  );
};

この方法は、最も柔軟な方法ですが、コード量が増えてしまうという欠点があります。

これらの欠点を克服するために、上記の代替方法を使用することができます。


arrays reactjs react-proptypes


Reactでボタンクリックを感知!onClickイベントハンドラーのわかりやすい解説

React JSにおいて、onClickイベントハンドラーは、ボタンやリンクなどの要素をクリックした際に実行する処理を定義するために使用されます。これは、ユーザーとのインタラクションを可能にし、動的なWebアプリケーションを構築する上で重要な要素となります。...


Reactで発生する「Uncaught Invariant Violation: Rendered more hooks than during the previous render」エラーの徹底解説

このエラーが発生する主な原因は次のとおりです。条件付きレンダリング内でフックを使用すると、条件によってフックの数がレンダリングごとに変化する可能性があります。上記の例では、useEffect フックは count が 0 の場合のみレンダリングされます。しかし、setCount を呼び出すと count が 1 になり、useEffect フックがレンダリングされなくなります。...