2016年3月31日
生のReactを知ろう – JSX、Flux、ES6、Webpackを使わず…
本記事は、原著者の許諾のもとに翻訳・掲載しております。
(編注:2016/07/29、いただいたフィードバックをもとに記事を修正いたしました。)
免責事項: 私はJSX、Flux、 ES6 、そして webpack を非常に気に入っています。これらのツールについては他のシリーズで話します。
React.jsが騒ぎを起こしているのはご存知の通りです。確かに、 XMLHttpRequest
以来の良いツールです。しかし、調査に数時間を費やした挙句、あまりに多くの用語に 圧倒された だけで終わっていないでしょうか。JSX、flux、ES6、webpack、react-routerが使える今、 他に必要なのは React の使い方を説明してくれる人だけです。
喜んでください、それがまさに当シリーズでやろうとしていることです。信じられませんか?大丈夫、 2分後、 初めてのReactアプリを作った後には納得いただけるでしょう。何もダウンロードせずに、です。次の練習をやってみてください。
練習 1 シングルファイルのReact.jsアプリを書こう
JavaScript、CSS、HTML を使ったことはありますか。いいですね。それならこの練習ができます。
この練習の成果物は、あなたが作る最初のReactアプリを含むHTMLファイル1点です。3つのステップがあります。
ステップ 1
このHTMLを新規ファイルにコピーし、適当な場所に保存しましょう。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>I'm in a React app!</title>
</head>
<body>
<div id="react-app"></div>
<script src="https://cdn.jsdelivr.net/react/0.14.0-rc1/react.js"></script>
<script src="https://cdn.jsdelivr.net/react/0.14.0-rc1/react-dom.js"></script>
</body>
</html>
このHTMLファイルには2つの重要な役割があります。レンダリングしたコンテンツ(id react-app
と共に)が動く div
を作成し、Reactが動く2つのライブラリファイルをロードします。
コピーできたら、次に進みましょう。
ステップ 2
HTMLファイルの末尾に、次のスクリプトを新規 <script>
タグに入力します。
コピー&ペーストではなく、入力するのはなぜでしょうか。タイプすることで、各コマンドのプロセスしながら、それらが頭の中にも叩き込まれるからです。一方、コピー&ペーストをした場合、賢くなったような快感が一瞬得られるだけです。ただ快感が欲しいのなら、この記事を読むのをやめて、flappy birdか何かで遊んだほうが手っ取り早いでしょう。
var rootElement =
React.createElement('div', {},
React.createElement('h1', {}, "Contacts"),
React.createElement('ul', {},
React.createElement('li', {},
React.createElement('h2', {}, "James Nelson"),
React.createElement('a', {href: 'mailto:james@jamesknelson.com'}, 'james@jamesknelson.com')
),
React.createElement('li', {},
React.createElement('h2', {}, "Joe Citizen"),
React.createElement('a', {href: 'mailto:joe@example.com'}, 'joe@example.com')
)
)
)
ReactDOM.render(rootElement, document.getElementById('react-app'))
ちょっとした仕事ですね。しかし、繰り返し入力したことで、 createElement
メソッドの概念がつかめるとよいのですが。まだ見えてこない、という人にはステップ3が役立つでしょう。
ステップ 3
WebブラウザでHTMLファイルを開き、アウトプットが次のようになっていることを確認してください。
どうでしょうか。良かった、分かりましたね。あなたは初めてのReact.jsアプリを npm
さえインストールせずに作ってしまいました。お祝いを兼ねて、その機能を見ていきましょう。
Reactの導入
基本的に、ReactはHTMLをJavaScriptでレンダリングするツールです。 ReactDOM.render
は、 ReactElement
オブジェクトを使って、何をレンダリングするかを説明し、指定された DOM nodeに結果を追加します。しかし、 ReactElement
はどうやって作るのでしょうか。ここで React.createElement
の出番です。
React.createElement
は3つのパラメータを引数にとり、 ReactElement
を返します。 Reactのドキュメンテーション にはこのように記述されています。
createElement(string/ReactClass type, [object props], [children ...]) -> ReactElement
type
引数が、使用するHTML要素のタイプを指定します。また、カスタム要素も指定します(後で説明します)。 props
引数はどの属性がHTML要素に定義されているかを指定する方法です。練習に出てきた mailto
リンクから推測できたかもしれません。最後に、 children
引数は、返された要素のコンテンツに使われる文字列、 ReactElement
オブジェクト(あるいはその配列)です。 children
を除外するか指定するか選ぶことで、 ReactElement
1つか、ツリー全体を返します。
createElement
は素のJavaScriptなので、ループ、 if
文、その他JavaScriptで行えるものなら何でも挿入できます。さらに、JSONに格納されたデータに簡単に代入することも可能です。例えば、連絡先のリストを持っているものの、e-mailアドレスのないコンタクトはレンダリングしたくない場合、次のような記述が考えられます。
var contacts = [
{key: 1, name: "James Nelson", email: "james@jamesknelson.com"},
{key: 2, name: "Bob"}
]
var listElements = contacts
.filter(function(contact) { return contact.email; })
.map(function(contact) {
return React.createElement('li', {key: contact.key},
React.createElement('h2', {}, contact.name),
React.createElement('a', {href: 'mailto:'+contact.email}, contact.email)
)
})
var rootElement =
React.createElement('div', {},
React.createElement('h1', {}, "Contacts"),
// If your `children` is an array, you'll need to give each one a unique `key`
// prop. I'll explain why a little later.
React.createElement('ul', {}, listElements)
)
ReactDOM.render(rootElement, document.getElementById('react-app'))
すっきりしています。つまりReactは非常に多弁なJavaScriptベースのテンプレート化システムであると言えます。しかし… それでは熱心に評価される理由になりません。何が特長なのでしょうか。
コンポーネント
React.createElement
のタイプシグネチャ内の小さな ReactClass
に気づいたでしょうか。使用しないので省きましたが、何を意味するか分かりますか。
ドラムロールの音をください、 答えです。「 React.createElement
は標準HTMLに限定されない」。オリジナルのコンポーネントを作ることもできるのです。
どうやって? React.createClass
を使って。
var ContactItem = React.createClass({
propTypes: {
name: React.PropTypes.string.isRequired,
},
render: function() {
return (
React.createElement('li', {className: 'Contact'},
React.createElement('h2', {className: 'Contact-name'}, this.props.name)
)
)
},
});
この小さなスニペットは ContactItem
と呼ばれる新規コンポーネントを定義します。HTML要素と同様に、 ContactItem
は属性のリスト( props
と呼びます)を受け入れます。HTML要素と異なるのは、どんな props
でも指定できることです。
上述のコンポーネントは次のように使えます。
var element = React.createElement(ContactItem, {name: "James K Nelson"})
そして予想どおり、 element
にはコンポーネントの render
関数が返す値が含まれます。
children
引数を createElement
に渡す場合、その値は this.props.children
の下で取得できます。
次の練習で理解度をテストしてみましょう。
練習 2 コンタクトリストのリファクタリング
学習したことを使って、練習1で書いた答え、特に次の点をリファクタリングしましょう。
- 3つのプロパティ、
name
、email
とdescription
を受け入れるContactItem
クラスを作る。 - e-mailアドレスを持たないコンタクトを選別する。
- データを
createElement
に直接渡す代わりに、配列に格納する。
次のデータを使ってください。
var contacts = [
{key: 1, name: "James K Nelson", email: "james@jamesknelson.com", description: "Front-end Unicorn"},
{key: 2, name: "Jim", email: "jim@example.com"},
{key: 3, name: "Joe"},
]
終わったら、次のfiddleと照らし合わせてみてください。
propTypes
練習 2の私の答えでは、 propTypes
オブジェクトに2種類の値、 isRequired
が付いている値と付いていない値を使っていることに気づいたでしょうか。このサフィックスは、指定されたプロパティが 必ず React.createElement
に渡されなければならないことを示しており、Reactの全ての prop types に適用できます。
しかし、ちょっと待ってください。 propTypes
オブジェクトは実際のところ 何をしている のでしょうか。
ほとんどの場合、 propTypes
は 何もしていない というのが答えです。事実、完全になくしてもアプリは正確に機能します。ではなぜそこにあるのでしょう。
propTypes
はデバッグを行うメカニズムなのです。これによってReactは createElement
に渡された props
引数が有効かどうかをリアルタイムでチェックします。正しくない場合はReactはコンソールに警告を出します。
この手引きで propTypes
を紹介するのは、それが必須事項ではなくとも、 長い目で見ると多くの無駄を防ぐことになるから です。そして私のニュースレターに登録するとダウンロードできる、Cheat Sheet(PDF)を印刷しておけば、より労力を軽減できます。話を元に戻します。ここまででデータを表示させる方法が分かりました。次に更新の仕方を学びましょう。
Get the PDF cheatsheet!
First Name
Email Address
Subscribe to my Newsletter
株式会社リクルート プロダクト統括本部 プロダクト開発統括室 グループマネジャー 株式会社ニジボックス デベロップメント室 室長 Node.js 日本ユーザーグループ代表
- Twitter: @yosuke_furukawa
- Github: yosuke-furukawa