Help us understand the problem. What is going on with this article?

React入門 ~PropTypes編~

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

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をあまり活用できていなかったりします(苦笑)
なので、今回記事を書きながら、あーこういうことできるものだったんだなと改めて思いました。

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

参考リンク

h-yoshikawa
精神疾患持ちのWebプログラマー。 とりあえず興味のあること、色々やってます。 (リンクは個人ブログです)
https://changeofpace.site
froide
Webサービスやモバイルアプリの受託開発。アジャイルをベースとした月額制のラボ型契約。
https://froide.co.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした