対象読者
- JavaScriptとWeb開発の基礎に理解がある方
- Reactに興味/関心があり、これから学び始める方
前提環境
筆者の検証環境は以下の通りです。
- macOS Sierra 10.12
- Node.js v8.9.4/npm 5.6.0
- React 16.2.0
- prop-types 15.6.0
Propsにはどんなデータを渡せばよいのか
Reactを使う機会が増えていくにつれて、他人が作ったコンポーネントを触る機会も増えていきます。連載第3回の「React×Material-UIでモダンなUIを実装する」で取り上げたmaterial-uiなどは典型的な「他人が作ったコンポーネント」ですね。数カ月前の自分自身が書いたコードも他人のものと考えたほうがいい、とする説もあるので、一人で開発していても期間が長くなれば、見覚えがないコンポーネントをメンテナンスする機会はやはり増えていくと思ったほうがいいでしょう。
さて、他人が作ったコンポーネントを使う場合、どんなことで困るでしょうか。例として、第4回の「Reactによるフォーム/リストの基本」に出てきたリスト1のコンポーネントについて考えてみます。
<List posts={this.state.posts} />
Listコンポーネントは、配列形式の投稿データ(posts)を受け取ることで投稿を並べて表示する機能を持ったコンポーネントでした。所定のデータ形式でデータを渡せば、よしなに表示してくれる。適切な粒度の責務を持った良いコンポーネントです。
さて、ここで問題になるのが「postsに渡す『所定のデータ形式』とは一体何なのか」ということです。実装を見に行けば分かる、というのはごもっともなのですが、コンポーネントの実装コードの中から「this.props.***」を一つひとつ探して、そのデータ型が何なのかを推測していくのは、根気のいる作業ですね。
では、コンポーネント一つひとつにPropsのデータ型を記述した仕様書を書けばよいのでしょうか。それとも、それに近い内容のコメントを記述しておけばよいのでしょうか。
恐らく、それらの方法はあまり現実的ではありません。プログラムを変更したら仕様書を変更する文化自体は悪いものではありませんが、コンポーネント単位で行うのは、あまりにも膨大で煩雑な作業になってしまいます。
Propsの型を簡単に知るための、良い方法がほしいところです。
prop-types
もし、コンポーネントのコード内にPropsの型が書いてあって、その型の通りにデータが渡されているのかをチェックしてくれる機構があれば、別途仕様書を用意したり、仕様書通りにPropsが渡せているかチェックしたりといった、根気の必要な作業をする必要がなくなります。
こうした課題を解決するためにFacebookが用意しているのが、今回紹介する「prop-types」というライブラリです。これは、Propsの型情報をJavaScriptのコードとして定義し、コンポーネントに付加情報として加えることで、Propsに渡されたデータをチェックできるようになるツールです。
導入するにはリスト2のコマンドを実行します。
$ npm install prop-types
以降、本記事では、ライブラリ名を「prop-types」、ライブラリからインポートしたモジュール名を「PropTypes」、コンポーネントに定義するプロパティ名(次項で紹介します)を「propTypes」と表記します。
コンポーネントへの定義
イメージをつかんでもらうために、前述のListコンポーネントに型情報を付加した場合のサンプルを紹介します(リスト3)。
import PropTypes from 'prop-types'; class List extends Component { render() { ... } } List.propTypes = { // (1) // posts属性は配列である posts: PropTypes.arrayOf( PropTypes.shape({ // 各プロパティの型を明示する // nameは文字列型の必須項目 name: PropTypes.string.isRequired, // ageは配列のうちどれかひとつに一致する必須項目 age: PropTypes.oneOf([ "teen", "twenties", "thirties", "fourties", "fifties" ]).isRequired, // bodyは文字列型の必須項目 body: PropTypes.string.isRequired }) ) };
prop-typesライブラリを用いた型情報は、(1)のようにコンポーネントに「propTypes」という名前のオブジェクト型プロパティを追加することで定義されます。細かい記法については後述しますが、リスト3のサンプルを眺めてみると「posts」がどんな構造を持ったデータなのか、少し分かってくるのではないでしょうか。
チェック機構
コンポーネントに型情報を定義できたことで型を認識しやすくなりましたが、prop-typesライブラリの本来の機能はデータのチェックです。propTypesプロパティに定義した型と異なる構造のデータが渡された場合に、コンソールにエラーログが表示されます。
例として、先ほどpropTypesプロパティを定義したListコンポーネントに、bodyを数値型にしたオブジェクトを渡してみましょう。bodyは文字列型で定義したので、何らかの反応があるはずです。
<List posts={[ { name: "taro", age: "teen", body: 0 } ]} />
このコードを実行すると、コンソールには図1のエラーメッセージが表示されます。
数値型ではなく文字列型を期待していると警告されました。コンポーネントの使い方を誤った場合には、こうして警告を出してもらえるので、デバッグ時には非常に有用です。
ただし、これはあくまでも警告です。今回のケースでも、0はテキストとして問題なく表示されました。アプリケーションを強制終了させる形でエラーの存在を認識させるタイプのツールではなく、エラーログを監視することでデバッグをやりやすくするツールとして認識してください。
[コラム]React.PropTypes
インターネット上でReactについての古い文献を調べると、次のような呼び出し方をしているサンプルに遭遇することがあります。
import { Component, PropTypes } from 'react';
実は、Reactのバージョン15系までは、PropTypesモジュールはReactの一部として提供されていました。2017年の夏、Reactがバージョン16.0.0になったタイミングで、諸事情から独立したライブラリとして提供されることになり、現在に至ります。そんなわけで、今回紹介するprop-typesライブラリのバージョンは独立当時のReactのバージョンである15.6.0がそのまま使われているのです。
2017年以前の文献を検索する際には、こうした事情に留意してください。