読者です 読者をやめる 読者になる 読者になる

Reactのチュートリアルをやってみた

完全に自分用メモ。

Thinking in Reactというチュートリアルを最小webpack構成で試した:

ishikuro/thinking-in-react-webpack-minimum · GitHub

React + Fluxの自分メモ

Webフロントエンドのプログラミングは、jQueryによる素朴なDOM操作から、AngularJSのような双方向バインディングへ移行してきた。しかしWebがコンポーネント指向に進むに従って、状態の管理が分散しがちであることが問題であった。

そこでFacebookが新世代のパラダイムを提案している。コンポーネント指向、仮想DOM、単方向バインディングなViewライブラリのReactを開発し、Fluxという単方向データフローのアーキテクチャを推奨した。

Fluxはアーキテクチャの名前であり、実装に規定はない。従ってgithubでもFluxアーキテクチャの実装が乱立している。今回はReactと、Flux亜種のひとつであるReduxという組み合わせを、Webpackを使って学習した。

これまで、自分でもAngularJS世代(双方向バインディング世代)のVue.jsで開発をしてきたが、きちんとしたデータフローを作ろうとすると自然とFluxっぽい設計になっていた。最上位VueコンポーネントをRootとして、状態はRootへ集約して、子コンポーネントが拾うユーザアクションは全てRootに伝える。Rootにビジネスロジックを持たせて、そこでデータを編集した状態を子コンポーネントに伝播させていってたりとか。Fluxはそういう手法を明確にレールにした印象。

React

Tutorial

Thinking in React

ファイル構成

webpack.config.js: src/*.jsをコンパイルして, dist/bundle.jsへ配置
dist/
  + index.html: bundle.jsをロードするだけ
src/
  + app.js: reactのimportと、実コードを書く

webpack.config.js

module.exports = {
  entry: [
    './src/app'
  ],
  output: {
    path: 'dist',
    filename: 'bundle.js'
  },
  module: {
    loaders: [{
      test: /\.js$/,
      loader: 'babel'
    }]
  }
};

dist/index.html

<!DOCTYPE html>
<html>
  <head>
    <title>Thinking in React</title>
  </head>
  <body>
    <script src="bundle.js"></script>
  </body>
</html>

コンパイル方法

$ npm install -g webpack
$ npm install --save-dev babel-loader
$ npm install --save react
$ webpack
$ open dist/index.html

以下はThinking in Reactより。箇条書きは意訳でもなく、読書メモ的なもの。

Step 1: UIをコンポーネントに分割して名前をつける

  • UI要素を箱で囲っていって、名前をつけていく。それがコンポーネントになる。
  • "single responsibility principle" 1つのコンポーネントには1つの責務だけを負わせる。
  • information architectureに注意。JSONのデータモデルと視覚化されたUIがうまく一致するのが良い構造だ。

  • FilterableProductTable

    • SearchgBar
    • ProductTable
      • ProductCategoryRow
      • ProductRow
      • ProductRow
      • ...
      • ProductCategoryRow
      • ProductRow
      • ProductRow
      • ...

Step 2: Reactで静的なバージョンを作ってみる

  • まずはインタラクションが無いバージョンを作ってみる。タイプ量が膨大だが考えることは少ない。
  • データモデルを描画を意識する。親コンポーネントから子コンポーネントへのデータフローにはpropsを使う。stateは現段階では使ってはいけない。それが必要になるのはインタラクションを追加するときだけだ。
  • 書くときはトップダウンでもボトムアップでも良い。小さいサンプルではトップダウンが楽だ。大きいプロジェクトではボトムアップにしてテストを書く。
  • このステップで作ったコードは、データモデルをあらわすコンポーネントライブラリになる。

Step2のコードを入れて、コンパイルしてみる。

Reactはwebpackを使ってbundleしてやるので、

import React from 'react';

を一番上に付け加える。

Step 3: 最小のUI stateを特定する

  • インタラクティブにするために、Reactではstateを使ってデータモデルへ変更を伝える。
  • DRYに沿って作る。最小のmutable stateを特定する。(富豪的に考える。キャッシュはひとまず考えない)
    1. 親か流れてくるpropsはstateにはしない
    2. 時間で変化しないものはstateにしない
    3. 他のpropsやstateから計算できるものはstateにしない

次のデータ一覧のうち*印をつけたものが今回のstate

Step 4: stateがどこに伝播するのか決める

ProductTableはSearchBarのフィルターを使う。ここでまとめるようなコンポーネントはFilterableProductTableである。よってフィルターテキストやチェックボックスのstateはFilterableProductTableに持たせる。子コンポーネントにはpropsを使って渡す。

Step 5: 子から親へのデータフローの追加

  • SearchBarからFilterableProductTableへ変更を伝えるコードを追加する。
  • Reactの方法では2wayバインディングよりもコード量は増えるが、明示的で分かりやすい。
  • inputタグのvalueは常に親からのpropsを反映している。
  • inputタグのvalueに変更があれば、SearchBarのhandleChange()が呼ばれ、その中で、prop.onUserInputというコールバックが呼ばれている。(propsにはコールバックを指定することもできる。)
  • このコールバックは親のFilterableProductTableのstateを変更するものである。 f:id:ishn:20150831145951p:plain

Flux(Redux)は次回。