Skip to content

Instantly share code, notes, and snippets.

@hakatashi
Last active October 19, 2016 23:54
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hakatashi/b5aca36d58bb2c91b73ac9293c6af9fb to your computer and use it in GitHub Desktop.
Save hakatashi/b5aca36d58bb2c91b73ac9293c6af9fb to your computer and use it in GitHub Desktop.

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
Copy link

プロ

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment