React入門 ~PropTypes編~

公開:2020/09/23
更新:2020/10/18
7 min読了の目安(約6500字TECH技術記事

React 入門記事、第3弾。
今回はコンポーネントに渡す props の使用を補助するものであるPropTypesについて書きました。

この記事は、過去に Qiita および個人ブログへ投稿した記事に一部加筆・修正をしたものです。

PropTypes とは?

React で使用するコンポーネントには props を渡して、レンダリング内容に変化をつけたりできます。
React での開発にあたり、ほぼ必須の存在であるものの、通常ではどんな値でも受け取ることができてしまいます。
(TypeScript であればまた事情が変わってきますが)
そのため、想定と違う値が渡されると予期しない動作をする可能性があります。

それを防ぐため、渡された値の型チェックを行うのがPropTypesです。
元々は React 本体に組み込まれていましたが、バージョン15.5よりprop-typesという別パッケージとして切り分けされました。

インストール

$ yarn add prop-types

今回の使用バージョンは15.7.2です。

使い方

React 公式ドキュメントはこちら。
React - Doc - PropTypes を用いた型チェック

基本的な使い方

まずは簡単な使い方から。

App.js

import React from 'react';
import PropsTypesComponent from './PropTypesComponent';

const App = () => {
  return (
    <PropsTypesComponent name="太郎" />
  )
}

export default App;

PropsTypesComponent.js

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

const PropTypesComponent = props => {
  return (
    <h2>Hello {props.name}</h2>
  );
}

PropTypesComponent.propTypes = {
  name: PropTypes.string
};

export default PropTypesComponent;

ライブラリを import

import PropTypes from 'prop-types';

props ごとのバリデーションを記述

コンポーネント.propTypes = {
 props名: PropTypes.バリデーションの種類
}


今回の場合

PropTypesComponent.propTypes = {
  name: PropTypes.string
};

これだけでバリデーションチェックが行われ、無効な値が渡された場合は DevTools のコンソールに Warning が出力されます。
上記の例では問題ありませんが、例えば PropsTypesComponent に渡している name の値を1など、string 以外の値にしてみます。
すると、以下のような Warning がコンソールに出力されているはずです。

warning.png

※1つ注意点として、このバリデーションチェックはパフォーマンス上の理由から開発モードの場合のみ動作します。

バリデーションの種類

数値

PropTypes.number

受け付ける例

1
1.0

文字列

PropTypes.string

受け付ける例

"太郎"
"1"

真偽値

PropTypes.bool

受け付ける例

true
false

一応補足として、あくまで真偽値なので"true"などはダメです。文字列扱いなので、バリデーションに引っ掛かります。

配列

PropTypes.array

受け付ける例

[1, 'A']
[{ id: 'A'}, { id: 'B' }]

配列であれば、その中の値の型までは問わないため非推奨のようです。
中の値の型までチェックする場合はarrayOfを使います。

PropTypes.arrayOf(バリデーションの種類)

// 例
PropTypes.arrayOf(PropTypes.number)

受け付ける例
※ PropTypes.arrayOf(PropTypes.number) の場合

[1, 2, 3]

オブジェクト

PropTypes.object

受け付ける例

{ a: 'A', b: 'B' }
など

オブジェクトであれば、その中の値の型までは問わないため非推奨のようです。
中の値の型までチェックする場合はobjectOfshape、もしくはexactを使います。

objectOfは特定の型のみの場合。

PropTypes.objectOf(バリデーションの種類)

// 例
PropTypes.objectOf(PropTypes.number)

受け付ける例
※ PropTypes.objectOf(PropTypes.number) の場合

{ a: 1, b: 2 }

shapeは型がバラバラの場合。

PropTypes.shape({
  props名: バリデーションの種類,
  props名: バリデーションの種類
})

// 例
PropTypes.shape({
  num: PropTypes.number,
  str: PropTypes.string
})

受け付ける例
※上の設定例の場合

{ num: 1, str: '太郎' }

exactも型がバラバラの場合です。
shapeとの違いは、バリデーション定義した以外のものがオブジェクトに追加されているとバリデーションに引っ掛かります。こちらの方がより厳密に props をチェックする感じです。

PropTypes.exact({
  props名: バリデーションの種類,
  props名: バリデーションの種類
})

// 例
PropTypes.exact({
  num: PropTypes.number,
  str: PropTypes.string
})

受け付ける例
※上の設定例の場合

{ num: 1, str: '太郎' }
// ここにこの二つ以外のキー、値があると警告

関数

PropTypes.func

受け付ける例

() => {
  console.log('func');
}

シンボル

PropTypes.symbol

受け付ける例

Symbol()
Symbol('test')

恥ずかしながら自分はシンボルって何?状態だったので調べたのですが、ES6 で追加された新しいプリミティブのデータ型だったのですね。

でも、いまいち使い方がよくわからない...。

特定の値のいずれかの場合

PropTypes.oneOf(['値1', '値2'])

// 例
PropTypes.oneOf(['A', 'B', 'C'])

受け付ける例
※上の設定例の場合

'A'
'B'
'C'

いろんなデータ型が渡される可能性がある場合

PropTypes.oneOfType([
  バリデーションの種類,
  バリデーションの種類
])

// 例
PropTypes.oneOfType([
  PropTypes.number,
  PropTypes.string
])

受け付ける例
※上の設定例の場合

1
'1'
'A'

クラスオブジェクト

PropTypes.instanceOf(クラス名)

// 例
PropTypes.instanceOf(Date)

受け付ける例
※上の設定例の場合

new Date()

React Element

PropTypes.element

受け付ける例

<Test /> // 独自定義のコンポーネント
<p>Test</p>

ちなみにelementTypeというものもあるのですが、elementとの違いや、どういう値を想定したものなのかがよくわかりませんでした...。

レンダリングできるもの

PropTypes.node

受け付ける例

1
'A'
['a', 'b']
<p>Test</p>
<Test /> // 独自定義のコンポーネント

数値、文字列、配列、React Element であればいいようです。
真偽値やオブジェクトはバリデーションに引っ掛かりました。

必須

PropTypes.バリデーションの種類.isRequired

// 例
PropTypes.number.isRequired
PropTypes.any.isRequired // 型は任意

カスタムルール

// カスタムルールの定義
const customProp = (props, propName, componentName) => {
  if (!/test/.test(props[propName])) {
    return new Error(
      'Invalid prop `' + propName + '` supplied to' +
      ' `' + componentName + '`. Validation failed.'
    );
  }
}

// カスタムルールの使用
コンポーネント名.propTypes = {
  props名: customProp
}

この例は props の値にtestという文字列が含まれているかチェックするものです(公式ドキュメントのコードをベースにしています)

propsのデフォルト値

defaultPropsを使って、props のデフォルト値を設定できます。
もしその props に値が渡されなかった場合は、このデフォルト値がセットされます。
また、バリデーションチェックと並行して使用している場合は、このデフォルト値セットが行われた後でバリデーションチェックが行われます。

コンポーネント名.defaultProps = {
  props名:}

// 例
PropTypesComponent.defaultProps = {
  defaultValue: 'default'
}

ずらっとルールを書いていきましたが、実は自分はこのPropTypesをあまり活用できていなかったりします...。
なので、今回記事を書きながら、こういうことできるものだったんだなと改めて思いました。
→ 最近は個人開発で使うようにしていますが、TypeScript を使うようになったら使わなくなりそう...。

渡す props が多いコンポーネントだとルールを定義するのが大変ではあります。
ただ、そのルールを見ればどんな値が渡されてくるのか、またそのコンポーネントを使用するにはどんな値が必要なのか一目瞭然でわかります。
ぜひ今後活用していきたいですね。

参考リンク

シリーズ記事リンク