React学習 その3 : propsについて

前回の記事では、コンポーネントの作成について勉強できました

今日は、Reactのpropsというデータを管理するためのメカニズムになります。

PropsとStateの違いについて

Props(プロップス):

  • propsは、親コンポーネントから子コンポーネントにデータを渡すために使用される。
  • propsは読み取り専用であり、コンポーネント内で変更することはできない。
  • propsは外部から渡されるため、コンポーネント内部では不変となる。
  • 親コンポーネントが子コンポーネントにデータを渡すためのメカニズムとして使用され、コンポーネント間のデータの受け渡しに便利。

気になったのが、stateも同じデータを管理するものだったと思うので、

State(ステート):

  • stateは、コンポーネント内部で管理されるデータの状態を表現する。
  • stateはコンポーネントによって変更可能であり、setStateメソッドを使用して更新することができる。
  • stateはコンポーネントに固有であり、そのコンポーネント自体が保持するデータになる。
  • stateの変更によって、Reactはコンポーネントを再レンダリングして、変更をUIに反映する。

propsとstateの違いとしては、

propsは外部から渡される読み取り専用のデータであり、コンポーネント内で変更することはできないようです。一方、stateはコンポーネント自体が管理する可変のデータであり、コンポーネント内で変更が可能となるようです。

例えば、親コンポーネントから子コンポーネントにユーザー名を渡す場合、propsを使用するようでした。ユーザーがボタンをクリックしたときに表示されるテキストを変更する場合、stateを使用してコードを記述していました。

ステートレス関数型コンポーネントに props を渡す

上記でまとめた通り、
React では props、つまりプロパティを子コンポーネントに渡すことができました。
たとえば App コンポーネントがあり、そこでステートレス関数型コンポーネントである Welcome という子コンポーネントをレンダーするとします。 次のように記述することで、Welcome に user プロパティを渡すことができました。

<App>
  <Welcome user='Mark' />
</App>

作成したのはカスタムの HTML 属性であり、React によってサポートされ、コンポーネントに渡すことができます。 今回の例では、作成したプロパティ user がコンポーネント Welcome に渡されます。 Welcome はステートレス関数型コンポーネントなので、次のようにしてこの値にアクセスできます。

const Welcome = (props) => <h1>Hello, {props.user}!</h1>

この値のことを props と呼ぶのが標準的だそうで、
ステートレス関数型コンポーネントは、JSX を返す関数への引数として考えます。 関数本体で引数の値にアクセスすることができます。
クラスコンポーネントの場合は、こうした操作は多少異なるようです。

配列を props として渡す

配列を props として渡す方法として、学んだことは、

JSX 要素に配列を渡すには、配列を JavaScript として扱い、中括弧で囲む必要があるそうです。

下記のコードのようになりました。

<ParentComponent>
  <ChildComponent colors={["green", "blue", "red"]} />
</ParentComponent>

これで、子コンポーネントから配列プロパティ colors にアクセスできるようになりました。
プロパティにアクセスするときは join() などの配列メソッドが使用できるそうです

const ChildComponent = (props) => <p>{props.colors.join(', ')}</p>

これによって、colors 配列のすべてのアイテムがコンマ区切りの文字列に結合され、<p>green, blue, red</p> が生成されました。

課題として、下記のようなものがありました。

コードエディターに List コンポーネントと ToDo コンポーネントがあります。 
ToDo コンポーネントから各 List をレンダーするときに、to-do タスクの配列 (たとえば ["walk dog", "workout"] など) が割り当てられた tasks プロパティを渡してください。
次に、List コンポーネントにあるこの tasks 配列にアクセスして、p 要素の中に値を表示してください。 join(", ") を使用し、props.tasks 配列をコンマ区切りリストとして p 要素に表示してください。
今日のリストには少なくとも 2 つのタスクを含め、明日のリストには少なくとも 3 つのタスクを含めてください。

解答はこんな感じになりました。

デフォルトの props を使用する

React にはデフォルトの props を設定するオプションもあるようでした。
デフォルトの props はコンポーネント自身のプロパティとしてコンポーネントに割り当てることができ、必要に応じて React によってデフォルトの props が割り当てられるようでした。
なので、prop の値が明示的に指定されていない場合に、その値を指定することができるようでした。 たとえば、

MyComponent.defaultProps = { location: 'San Francisco' }

 と宣言した場合は、特に指定しない限り、location という prop を定義して文字列 San Francisco を設定したことになります。
props が未定義の場合は、React によってデフォルトの props が割り当てられます。ただ、prop の値として null を渡した場合は null のままになるようです。

あくまで、defaultPropsは、初期値としての役割がメインということのようです。

デフォルトの props を上書きする

React の便利な機能として、デフォルトの props を設定することができるようです。
デフォルトの props を上書きするには、コンポーネントの props の値を明示的に設定する必要があるようです。

下記のような課題をして意味を理解しました。

ShoppingCart コンポーネントで現在、子コンポーネント Items をレンダーしています。 この Items コンポーネントにはデフォルトの props quantity があり、整数 0 に設定されています。 quantity に値 10 を渡してデフォルトの prop を上書きしてください。

上記のようにpropsの値を変更するとができました。

動的に変更するには、

・この後、勉強するstateを使用したり、

・今回のように親コンポーネントからプロパティの変更をする必要があるようです。

propTypes を使用して、期待する props を定義する

Reactで使用するデータのデータの型を指定したい場合、

React は、コンポーネントが正しい型の props を受け取ることを検証するための便利な型チェック機能を備えています。 たとえば、アプリケーションで API 呼び出しを実行して、配列にあると想定しているデータを取得し、prop としてコンポーネントに渡すとします。 コンポーネントで propTypes を設定して、データが array 型であることを要求することができます。 こうすることで、データが他の型である場合に、便利な警告がスローされます。

prop の型が事前にわかっている場合は propTypes を設定することをお勧めします。 defaultProps の定義と同じ方法で、コンポーネントの propTypes プロパティを定義できます。 こうすることで、与えられたキーの props が与えられた型であるかどうかがチェックされます。 handleClick という prop に function 型を要求する例を次に示します。

MyComponent.propTypes = { handleClick: PropTypes.func.isRequired }

この例では、PropTypes.func の部分で handleClick が関数かどうかをチェックします。
isRequired を追加することで、handleClick がそのコンポーネントに必要なプロパティであることを React に伝えます。
その prop が指定されていない場合は警告が表示されます。
また、func は function を表します。 JavaScript の 7 つのプリミティブ型の中で、function と boolean (bool と記述) の 2 つだけは通常と異なるスペルを使用します。 プリミティブ型に加えて、他にも利用可能な型があります。
たとえば、prop が React の要素かどうかをチェックできます。
オプションの一覧については ドキュメントを参照してください。

注: React v15.5.0 では PropTypes は React とは独立してインポートされます (例: import PropTypes from 'prop-types';)。

静的型チェックには TypeScript を使用するようです。

this.props を使用して props にアクセスする

props に渡そうとしている子コンポーネントが、ステートレス関数型コンポーネントではなく、ES6 クラスコンポーネントである場合はどうなるのかを学びました。

クラスコンポーネント自体を参照するときはいつでも、this キーワードを使用するようでした。
クラスコンポーネント内の props にアクセスするには、アクセスに使用するコードの前に this を置きます。 たとえば、ES6 クラスコンポーネントに data という prop がある場合、
JSX では 

{this.props.data} 

と記述します。

課題として下記のようなものがありました。

親コンポーネント App にある Welcome コンポーネントのインスタンスをレンダーしてください。 ここでは、Welcome に name という prop を付け、文字列の値を割り当ててください。 子要素 Welcome の中で、strong タグ内の name prop にアクセスしてください。

ステートレス関数型コンポーネントでの props の使用を復習する

propsの使い方についてのまとめとして、課題を行いました。

コードの解説としては、

const Camper = (props) =>
  <p>{props.name}</p>

では、アロー関数を使用して Camper コンポーネントを定義しました。

Camper.defaultProps = {name:'CamperBot'};

Camper コンポーネントのデフォルトプロパティを設定しました。
name プロパティのデフォルト値は 'CamperBot'を設定しています。
つまり、もし親コンポーネントから name プロパティが渡されなかった場合、デフォルトで 'CamperBot' が表示されます。

Camper.propTypes = {
  name: PropTypes.string.isRequired
};

Camper コンポーネントのプロパティの型を指定しました。
PropTypes.stringname プロパティが文字列であることを表しています。
また、isRequired を指定することで、name プロパティが必須であることを示しています。
つまり、もし親コンポーネントから name プロパティが渡されなかった場合、警告が表示されるようにしています。

注意点として

※上記のコードでは、Component.propTypesでエラーを吐きました。

理由としては、

  • propTypes を使用して、期待する props を定義する
  • でやった、

    注: React v15.5.0 では PropTypes は React とは独立してインポートされます (例: import PropTypes from ‘prop-types’;)。

    が原因でした。

    なので、App.jsファイルの先頭に
    import PropTypes from “prop-types”;
    を追加しています。


    型などの指定をする際は、TypeScript を使用した方がいいようですね。

    ちょっと興味が出てきたので、TypeScriptについても時間ができたら学んでみたいですね。

    今日は、ここまでです〜

    また、次回に!!

    タイトルとURLをコピーしました