Skip to content

Instantly share code, notes, and snippets.

@hakatashi hakatashi/sig-web-09.md
Last active Oct 19, 2016

Embed
What would you like to do?

TSG 第9回Web分科会 カンペ

React(とflux)について学ぶ。

事前準備

Node.jsをインストールする。

Windows もしくは OS X

Node.js公式ページに行き、Current と書いてあるリンクをクリックするとインストーラーが落ちてくる。

あとは指示通りインストールを進めていけばよい。

Linux

nvmをおすすめする。

curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.2/install.sh | bash

でnvmをインストールしたあと、

nvm install node

で最新版のNode.jsをインストールする。

curl | bashをしたくない人は公式ページに従ってインストール。

Hello, World! (React)

まずはいつも通り Hello, World! から。

以下の内容を適当なファイル名(react.htmlとか)で保存し、ブラウザで開く。「Hello, World!」と表示されれば成功。

<!DOCTYPE html>
<html>
  <head>
    <script src="https://unpkg.com/react@15.3.2/dist/react.js"></script>
    <script src="https://unpkg.com/react-dom@15.3.2/dist/react-dom.js"></script>
    <script src="http://fb.me/JSXTransformer-0.12.2.js"></script>
    <script type="text/jsx">
      class HelloWorld extends React.Component {
        render () {
          return <h1>Hello, World!</h1>;
        }
      }

      ReactDOM.render(
        <HelloWorld/>,
        document.body
      );
    </script>
  </head>
  <body>
  </body>
</html>

Reactとは

Facebook社が2013年に発表したリアクティブUIフレームワーク。

DOMとデータを切り離すための思想と導入の容易さが受け入れられ、JS界隈で流行した。

また、後ほど話すfluxと呼ばれる思想の登場によってさらに爆発的に流行。去年ぐらいまでJS界隈で最もアツいライブラリだった。

「リアクティブ」とは

例えば文字列の配列からli要素を動的に生成する場合を考える。

生のAPIを使う場合、

const usersElement = document.createElement('ul');
usersElement.setAttribute('class', 'users');
document.body.appendChild(usersElement);

const users = ['aaa', 'bbb', 'ccc'];

users.forEach((user) => {
  const userElement = document.createElement('li');
  userElement.setAttribute('class', 'user');
  userElement.textContent = user;
  usersElement.appendChild(userElement);
});

jQeuryを使うと、

const $users = $('<ul/>', {'class': 'users'}).appendTo('body');

const users = ['aaa', 'bbb', 'ccc'];

users.forEach((user) => {
  $('<li/>', {'class': 'user', text: user}).appendTo($users);
});

これらは「配列から一つづつ値を取り出してその値を持つli要素を追加する」という手続きをナイーブに記述しているだけであり、「userクラスのli要素が配列の値を表現する」ということを記述していない。そのためUIを操作するコードは規模が大きくなるにつれて肥大化し、変更に対する影響が追いにくくなっていく。

このように「データに対して行う処理を最終的な結果に至るまで順に記述していく」のではなく、「データを加工する処理をいくつかのコンポーネントに分割し、それぞれの要素が行うデータの送受信のみを定義する」ことを「リアクティブプログラミング」と呼ぶ。

Reactはこの考えをDOMに適用したものである。

Reactの記法とJSX

で、先ほどの処理をReactで記述すると以下のようになる。

class User extends React.Component {
  render() {
    return <li className="user">{this.props.name}</li>
  }
}

class Users extends React.Component {
  constructor(props) {
    super(props);
    this.state = {users: []};
  }

  render() {
    const userNodes = this.state.users.map(user => <User name={user}/>);

    return <ul className="users">
      {userNodes}
    </ul>;
  }
}

const users = ReactDOM.render(
  <Users/>,
  document.body
);

users.setState({users: ['aaa', 'bbb', 'ccc']});

コードは長くなっているが、データをDOMに反映するまでの処理がコンポーネントに分割され、よりリアクティブになっている。

まず特徴的なのはコード中にHTMLの断片のようなものが直接記述されていることである。これはJSXというReactのコードを簡明に記述するための記法で、JavaScriptの文法を独自に拡張したものである。実際に動かすためにはコンパイルしてJSのコードに変換する必要がある。

JSXのコンポーネント記法はHTMLと似ているが結構異なる。タグ名に当たる部分を大文字で始めるとHTML要素ではなくReactコンポーネントを呼び出すことができる。

Reactの特徴の一つはVirtualDOMを用いて軽量に操作できる点である。例えば先ほどのリストの内容を変更する場合は、

users.setState({users: ['aaa', 'bbb', 'ccc', 'ddd']});

とすればul要素に新しいli要素を追加できるが、この時Reactは一旦ul要素を空にしてから再びli要素を4個追加するのではなく、差分であるdddのli要素のみを検出して追加することができる。一般にDOMの操作は様々な副効果を引き起こしてとても重いので、実際に変更があった部分のみを変更するのはとても重要である。

flux

fluxはReactで言うところのstateのようなものを、どのようなルールで管理するかを規定する枠組みである。言うなればクライアントサイドのMVCみたいなものである。

2014年に同じくfacebookが発表し、当初は懐疑的な意見が多かったものの後にReactとともに広く普及し、2014年から2015年のトレンドとなった。

(この直前に流行ったAngularを採用したプロジェクトは歯噛みをしたという)

ここでは詳しい説明は省くが、fluxは4種類のコンポーネントから構成され、その中をデータが一方向に流れていくモデルを想定する。Viewの部分は通常Reactで実装する。

fluxはライブラリやフレームワークではないので、複数の実装が存在する。一時は数十の実装が存在し戦国状態となっていたが、最近は以下の2つがメジャーどころとなっている。

実習

今回はReact.jsを使ってCTF分科会で使えそうなflag送信サイトを作ってみる。

以下のリンクから2つのファイルを保存する。flag-matcher.htmlを開くとページが表示されることを確かめる。
https://gist.github.com/hakatashi/faca529e065878d537381f47406b9574

以下の機能を実装してよう。

  • 問題のタイトルを正しく表示する
  • flagを入力してボタンを押すと合ってるかどうかcheckし、alertで結果を表示してくれる
  • 下のフォームから新しい問題を追加できるようにする

ヒント

  • 処理を書くべきところにTODOコメントを書いているので、参考に。

余力があれば

  • Solversを記録し、表示する
  • 問題のタイトルやフラグが空白ならエラーを出す
  • checkの結果をalertではなくいい感じに表示する
    • BootstrapのJSを読み込むと良いかも
  • LocalStorageあたりにデータを保存するようにする
    • マニアックにやるならIndexedDBとか(つらい)
  • ユーザーのリストを別途保持し、そこから選択するようにする
  • 問題作成者の情報を記録・表示する
  • 問題に得点の情報を持っておき、ユーザーごとのランキングをつくる
  • サーバーを書く(つらい)
    • やるならIsomorphicにしたいね
  • CSSをがんばる

参考実装

  • 問題のタイトルを正しく表示する
  • flagを入力してボタンを押すと合ってるかどうかcheckし、alertで結果を表示してくれる
  • 下のフォームから新しい問題を追加できるようにする
  • Solversを記録し、表示する

まで実装したものを以下に置いておいた。
https://gist.github.com/hakatashi/319a6a9e1683f151197bfe0d53b4ac47

差分はこちら。
https://gist.github.com/hakatashi/319a6a9e1683f151197bfe0d53b4ac47/revisions

@niconegoto

This comment has been minimized.

Copy link

commented Oct 19, 2016

プロ

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.