はじめに
Fullstack React: 30 Days of React の意訳です。
ちょいちょい読んでるのでせっかくなので訳そうと思った次第。飽きるまで続きます。かなり意訳です。
- Day1 - What is React?
- Day2 - What is JSX?
- Day3 - Our First Components
- Day4 - Complex Components
- Day5 - Data-Driven Components
- Day6 - State
- Day7 - Lifecycle Hooks
※補足: ってなってるのは、私の補足や思ったことなどです
本編
今日は再利用可能なコンポーネントの作り方とチームやアプリ感でそれらをシェアする方法を見て行きます。
なんとか2週目に入りましたね。ここまでは、基本的なReactの機能(props, state, life-cycle hooks, JSX, など)を学びました。このセクションではコンポーネントのアノテーティングを見ていきます。
PropTypes
コンポーネントの中では、propsがかなりたくさん使われているのに気がついたかもしれません。ほとんどの場合、これらのpropsには特定の型の値(stringやobjectなど)が渡されることを想定すると思います。Reactは、簡単にコンポーネントのAPIを公開できるようにするために、これらの型を定義、検証するためメソッドを提供します。
これはドキュメント化以外にも再利用可能なコンポーネントを作るという点においても良いプラクティスです。
React.PropTypes
オブジェクトを使うと、コンポーネントのプロパティが何の型であるべきかを定義することができます。
ES6クラススタイルのpropTypes
メソッドを使ってプロパティの型を定義することができます。
class Clock extends React.Component {
// ...
}
Clock.propTypes = {
// key is the name of the prop and
// value is the PropType
}
React.createClass()
を使う場合は以下のようになります。
const Clock = React.createClass({
proptypes: {}
});
コンポーネントのプロパティ名と型のセットを持つオブジェクトによって、プロパティの型が何であるべきかを定義することができます。
数日前に作ったHeaderコンポーネントをtitleプロパティを文字列型と定義する例は以下のようになります。
class Header extends React.Component {
// ...
}
Header.propTypes = {
title: React.PropTypes.string
}
React.PropTypes
に使える多くの型があります。使える型のリストを見てみましょう。
Basic types
type | example | class |
---|---|---|
String | hello | React.PropTypes.string |
Number | 10, 0.1 | React.PropTypes.number |
Boolean | true / false | React.PropTypes.bool |
Function | const say => (msg) => console.log("Hello world") | React.PropTypes.func |
Symbol | Symbol("msg") | React.PropTypes.symbol |
Object | {name: 'Ari'} | React.PropTypes.object |
Anything | whatever, 10, {} | |
A rendererable | 10, 'hello' | React.PropTypes.node |
レンダリング可能ならどんな型でもよい場合には、React.PropTypes.node
を使うことができます。
Clock.propTypes = {
title: React.PropTypes.string,
count: React.PropTypes.number,
isOn: React.PropTypes.bool,
onDisplay: React.PropTypes.func,
symbol: React.PropTypes.symbol,
user: React.PropTypes.object,
name: React.PropTypes.node
}
ここまで、プロパティを使って、親コンポーネントから子コンポーネントにコミュニケーションする方法を見てきました。また、子コンポーネントから親コンポーネントを関数を使ってコミュニケーションする方法も見ました。この方法は子コンポーネントから親コンポーネントを操作する場合に非常に多く使うパターンなのでよく覚えておきましょう。
Collection types
イテレータブルなコレクションをプロパティに渡すこともできます。コンポーネントのproptypeを配列として宣言するために、React.PropTypes.arrayアノテーションを使用できます。
また、配列にReact.PropTypes.arrayOf([])
を使用して特定の型のオブジェクトだけを持つように要求することもできます。
type | example | class |
---|---|---|
Array | [] | React.PropTypes.array |
Array of numbers | [1, 2, 3] | React.PropTypes.arrayOf([type]) |
Enum | ['Red', 'Blue'] | React.PropTypes.oneOf([arr]) |
React.PropTypes.oneOfType([types])
を使って、特定の型の配列を定義することもできます。
Clock.propTypes = {
counts: React.PropTypes.array,
users: React.PropTypes.arrayOf(React.PropTypes.object),
alarmColor: React.PropTypes.oneOf(['red', 'blue']),
description: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.instanceOf(Title)
]),
}
Object types
決まった形式のオブジェクトや特定のクラスのインスタンスを定義することもできます。
type | example | class |
---|---|---|
Object | {name: 'Ari'} | React.PropTypes.object |
Number object | {count: 42} | React.PropTypes.objectOf() |
Instance | new Message() | React.PropTypes.instanceOf() |
Object shape | {name: 'Ari'} | React.PropTypes.shape() |
Clock.propTypes = {
basicObject: React.PropTypes.object,
numbers: React.PropTypes
.objectOf(React.PropTypes.numbers),
messages: React.PropTypes
.instanceOf(Message),
contactList: React.PropTypes.shape({
name: React.PropTypes.string,
phone: React.PropTypes.string,
})
React types
親から子へReactの要素を渡すこともできます。これはテンプレートを定義し、そのテンプレートをカスタマイズするのにとても役にたちます。
type | example | class |
---|---|---|
Element | React.PropTypes.element |
Clock.propTypes = {
displayEle: React.PropTypes.element
}
エレメントを使う場合には、単一の要素を渡す必要があります。複数の要素を渡すことはできません。
// 正しくない
<Clock displayElement={
<div>Name</div>
<div>Age</div>
}></Clock>
// 正しい
<Clock displayElement={
<div>
<div>Name</div>
<div>Age</div>
</div>
}></Clock>
Requiring types
.isRequired
をつけることで、そのプロパティを必須にすることができます。
Clock.propTypes = {
title: React.PropTypes.name.isRequired,
}
そのプロパティが親から渡されないと動作しないような場合に、プロパティを必須にするのはとても役にたちます。
Custom types
最後に、関数を渡すことでカスタムタイプを定義することもできます。これは単一のプロパティのArrayのバリデーションに使えます。バリデーションがパスしない場合、関数はErrorオブジェクトを返す必要があります。
type | example | class |
---|---|---|
Custom | something_crazy | function(props, propName, componentName) {} |
CustomArray | ['something', 'crazy'] | React.PropTypes.arrayOf(function(props, propName, componentName) {}) |
Clock.propTypes = {
userWithName: (props, propName, componentName) => {
if (!props[propName] || !props[propName].name) {
return new Error(
`Invalid ${propName}: No name property defined
for component ${componentName}`
)
}
},
usersWithNames: React.PropTypes
.arrayOf((props, propName, componentName) => {
if (!props[propName] || !props[propName].name) {
return new Error(
`Invalid ${propName}: No name property defined
for component ${componentName}`
)
}
})
}
Default props
プロパティを設定したい場合もあると思います。例えば、以前作った <Header />
にタイトルを渡さない場合でも、タイトルには何かしらのタイトルを表示する必要があります。
デフォルト値の設定には、 defaultProps
を使います。
Header.defaultProps = {
title: 'Github activity'
}
型の定義やデフォルト値の設定は、コンポーネントの再利用や開発者間のコミュニケーションに役立ちます。次にセクションではスタイルの設定について見てきます。