POSTD PRODUCED BY NIJIBOX
POSTD PRODUCED BY NIJIBOX

ニジボックスが運営する
エンジニアに向けた
キュレーションメディア

2016年3月31日

生のReactを知ろう – JSX、Flux、ES6、Webpackを使わず…

James K Nelson

本記事は、原著者の許諾のもとに翻訳・掲載しております。

(編注: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つのプロパティ、 nameemaildescription を受け入れる 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はコンソールに警告を出します。

React console warning

この手引きで propTypes を紹介するのは、それが必須事項ではなくとも、 長い目で見ると多くの無駄を防ぐことになるから です。そして私のニュースレターに登録するとダウンロードできる、Cheat Sheet(PDF)を印刷しておけば、より労力を軽減できます。話を元に戻します。ここまででデータを表示させる方法が分かりました。次に更新の仕方を学びましょう。

Get the PDF cheatsheet!

First Name

Email Address

Subscribe to my Newsletter