前回の記事では、コンポーネントの作成について勉強できました
今日は、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.string
は name
プロパティが文字列であることを表しています。
また、isRequired
を指定することで、name
プロパティが必須であることを示しています。
つまり、もし親コンポーネントから name
プロパティが渡されなかった場合、警告が表示されるようにしています。
注意点として
※上記のコードでは、Component.propTypesでエラーを吐きました。
理由としては、
でやった、
注: React v15.5.0 では PropTypes は React とは独立してインポートされます (例: import PropTypes from ‘prop-types’;)。
が原因でした。
なので、App.jsファイルの先頭に
import PropTypes from “prop-types”;
を追加しています。
型などの指定をする際は、TypeScript を使用した方がいいようですね。
ちょっと興味が出てきたので、TypeScriptについても時間ができたら学んでみたいですね。
今日は、ここまでです〜
また、次回に!!