Rのつく財団入り口

最近の本や技術系の話などを書いてます。元はTRPG系サイトの入り口でした。

【感想】React入門 React・Reduxの導入からサーバサイドレンダリングによるUXの向上まで

React入門 React・Reduxの導入からサーバサイドレンダリングによるUXの向上まで

 タイトルどおり、JavaScriptフレームワークで有力なReactと大規模状態管理のReduxを中心に、仕事レベルの開発をターゲットにした本。フロントエンド急速強化月間ということで読みました。
 2018/2/19に出たばかりの最新の本、400ページクラスのしっかりした本です。

React入門 React・Reduxの導入からサーバサイドレンダリングによるUXの向上まで (NEXT ONE)

React入門 React・Reduxの導入からサーバサイドレンダリングによるUXの向上まで (NEXT ONE)

第1章:React・Reduxとは?

 おなじみReactの特徴、その他のライブラリとの比較では初期に流行ったBackbone.jsとAngular.jsが出てきます。
 この章から複雑なアプリでの状態管理用のReduxの話も登場し、解説記事でよく見るFluxアーキテクチャの図が出てきます。

  • View:Reactコンポーネントと同義
  • Action:単なるオブジェクトでdispatchするとStoreに渡される。商品の購入、モーダル表示も
  • Dispathcer:データの流れを管理。単なるEventEmitter(イベントを発火してデータを渡す人)で、ActionをStoreに渡す
  • Store:MVCのMに似ているが別物、アプリケーションの状態とロジックを保持

 僕もReduxの話で勘違いしていたのですが、ReduxはFluxアーキテクチャの一種のアーキテクチャで、npmでインストールできるものはJSライブラリで特にReact専用という訳ではないんですね。AngularやVue.jsとも使えるそうです。本書では以下のように説明しています。

  • 「アプリケーション内のすべての状態を一枚岩の大きなオブジェクトとして管理」
  • 「Actionをディスパッチするのが状態変更の唯一の手段で一方向」
  • 「状態の変更は副作用のない純粋関数(Reducerが担当、入力が同じなら出力も毎回同じ)で行う」

 Reducerのコード例も載っています。クラス(正確にはJSにはクラスないですが)ではなくただの関数。読書開始・読書終了などのアクションを受け取ったらそれぞれに応じた状態を返す処理。case文で分岐する方法も、定数reducersにアクションの数だけの関数オブジェクトの配列で持たせる方法もあり。配列やオブジェクトを渡す時は参照渡しでなくObject.assign()などを使ってコピーを渡すのが要注意…というところ。

第2章:create-react-appで開発を始めよう

 開発環境を整えて約束のHello Worldアプリケーションを作っていく章。
まずはJavaScript開発で必須のNode.jsのインストール。インストーラーを叩いていくだけですが、Windows/Mac両方のキャプチャを解説しています。
 これでnpmが使えるようになるので、Facebook製のReactプロジェクトが簡単に作れるようになるツール、create-react-appをnpm install -g create-react-appでインストール。

 任意のフォルダで create-react-app アプリ名するだけで、一式必要なファイルが生成されます。そして {作られたアプリ名フォルダ}/src/App.jsにAppコンポーネントを作成、npm startすればサーバーとして立ち上がって http://localhost:3000/ ですぐ動く、という流れです。
 JS界隈ではこういうライブラリ・ツールを「ボイラープレート」と呼ぶそうですが、RubyRailsのコマンド rails new アプリ名や、PHPのComposerを使ったコマンド composer create-project laravel/lalravel アプリ名 prefer-dist による手軽なアプリ作成みたいなものですね。JavaだとSpring Bootみたいなものでしょうか。
 実際の開発時はリポジトリで管理された開発対象のアプリケーションにではなく、ちょっとしたコンポーネントやライブラリの手元での動作確認なんかに使うそうですが、これは簡単でよいですね。

第3章:JSX

 Reactによる開発でほぼ必須になるFacebook製のJavaScript拡張言語、というか記法というかドメイン固有言語(DSL: domain-specific language)であるJSXの章。

  • コンポーネントの描画メソッドであるrender()関数の戻り値にHTML的に書く。
  • 予約語の重複避けでHTMLのclass属性はclassName属性、for属性はhtmlFor属性に。
  • JSXで<h1>React!</h1> と書くのは React.createElement("h1", null, "React!") と同義で、HTMLが複雑になるとJSXの方が分かりやすい。慣れの問題。
  • 最初に `import Rect from 'react'が必要。
  • JSX内で { someFunc('aaa') } など{}で関数や式が書ける。
  • トランスパイルされるので、普通にJS構文の変数や戻り値、関数の引数に使える。
  • HTMLタグの属性値には <input type="text" value={val}> のように式が書ける。
  • HTMLタグの属性名は onClick={}のようにローワーキャメルケース。
  • HTMLタグの子要素も <h1>{h2child}</h1> のように書ける。
  • <ul><li>...のような複数要素は子要素に配列を渡して実現。
  • 空要素は必ず < ..... /> で閉じないとエラー。
  • タグ名だけ後で変えたい時は、React.createElement 関数を使うと良い。

などなど基本のところ。
 JSXはGoogleで「JSX き」と入れると「JSX 気持ち悪い」「JSX キモい」が検索候補に出てきてしまったりする不遇の言語ですが(笑)、前にネットでもフロントエンド界隈で炎上っぽく議論になったりもしていました。外野からすると宗教みたいでコワいなあというところですが、結局のところは本書のように慣れの問題なのかなと思います。

 そしてJSXで記述されたコードをJavaScriptに変換してくれるトランスパイラ、Babelの紹介。

  • プロジェクト用のフォルダを作る
  • npm install --save-dev babel-cli babel-preset-react でコマンドからBabelを実行できるbabel-cliをインストール、そしてReactを使った開発で必要なプラグインを全部まとめてくれたbabel-preset-reactもインストール。

フォルダ構成の解説もありイメージが湧きやすいです。

# input.js に書いたReactコンポーネントをトランスパイル
./node_modules/.bin/babel -presets=react input.js --out-file output.js
# src配下のjsファイルを全て、lib配下に階層構造を保ってトランスパイル
./node_modules/.bin/babel -presets=react src --out-dir lib

 という具合です。他の言語、Javaなんかの慣習だとlibフォルダはアプリ本体や関連ライブラリをjarに固めたファイル群の置き場でテキストファイルは置かないので、libの下にjsファイルを置くのはなんか新鮮でした。

 続いて、タスクランナーのgulpやGruntに代わりもうデフォルトとなりつつあるモジュールバンドラーツール、webpackの話。

  • またプロジェクト用のフォルダを作る。
  • npm でwebpackをインストール。
  • 同じく、今度はbabel-cliでなくbabel-loader, babel-core をインストール。
  • React開発用に babel-preset-react をイントールするのは同じ。
  • React自体がいるので、react, react-domをインストール。
  • JSのソースでは、Reactは import React from 'react'; import ReactDOM from 'react-dom';のようにnpmで入れたものをインポートする。
  • 同じJSのソースでコンポーネントの定義などアプリ側の他のJSファイルは、import Hello from './Hello' のようにファイルの拡張子なしでインポートできる。
  • プロジェクトのルートにwebpackを動かすための設定ファイル webpack.config.js を作る。中はES6で追加されたモジュール形式で、実行の起点になるjsファイル、1つにまとめられる出力jsファイル、moduleフィールドの中に変換ルール(Babelを使うよ、.jsを変換するよ、プリセットはbabel-preset-reactだよ)を書く。
  • コマンドで ./node_modules/.bin/webpack --config webpack.config.js でwebpack実行。オプションは全部上記の設定ファイルの中。設定した出力jsファイルに、トランスパイルされてかつ1ファイルに纏められたjsファイルが生成。
  • この出力jsファイルをHTMLで普通に読み込めば、それだけでReactが動かせる。

 という流れで、webpackを使えば2度以上の手間だったのが1回のコマンドで済みますよとなります。 React開発に限らずJS界隈でのこのnpmやbabelやwebpackなどなどの話、初心者からすると慣れるまで混乱しがちなので詳しく書いてあり助かりました。
 あとよく出てくる import Xx from 'Yy'; のモジュールの書き方、絶対・相対パスであれば開発しているアプリ内の他のファイル、違う場合はwebpackがnpmで入れたものへの参照と認識して解決するんですね。この辺今まで気にせず流していたのでやっと理解できました。

第4章:Reactコンポーネント

 そしてReactの中核であるコンポーネントの話。

  • Functional Component: 引数にpropsを取り、JSXを返す関数。例ではアロー関数。これも立派なReact。
  • Class Component: class Hello extends React.component {.....のクラス形式。クラス形式だとpropsの他にstateがあり、ライフサイクルメソッドを使える。
ReactDOM.render (
  <Hello/>
  <Hello/>
);

のように独自HTMLタグのように書いていけば使える。こちらはReactエレメントといい、クラス定義に対応したインスタンスのような概念。

  • コンポーネント定義で2つの要素を並列に返したい時はFragmentコンポーネントを使うとできる。
  • Reactエレメント使用時に name="なにがし" と渡すと、コンポーネント側ではprops.nameのように受け取れる。文字列、数値、真偽値、配列、オブジェクト、関数、特別にchildrenとして子要素など、色々渡せる。
  • propTypes(prop-types)というライブラリをnpmで入れ、コンポーネント定義時に指定しておくと、各propsの型チェックをしてくれる。JSのデータ型の他にelement型やnode型、デフォルトや必須かなども指定できる。

 propTypesは入門記事なんかだと触れられていないことが多いので新しい情報でした。本格的なアプリになると必須になりそうですね。


 続いて状態を記録するstateの話。例としてJSフレームワークを使ったアプリの解説で頻出する、必殺のToDoアプリがここでも出てきます。他のReact本ですとToDoアプリ全体が1つのコンポーネントのことが多いですがこの本では、

アプリ全体がApp→入力フォームがTodoInput、→ToDo一覧がTodoList→1つ1つがTodoItem

コンポーネントを分割しており、よく見ていくと理解が深まると思います。最上位のAppコンポーネントのthis.state の中に配列tasksで持つ形です。ToDo追加のメソッドも最上位のAppの中に持ち、子コンポーネントにpropsの中に入れて渡すことが可能。
注意すべきは変更を検知するバインディングの話があるので、state変数は直接変更はダメで必ずsetStateメソッド経由で必ずアクセスする、配列は取扱い注意...というところ。このへん、Vue.jsも学んでいると同じようなところも違うところもあって面白いです。

 そしてイベントハンドリングはタグに onClick={this.handleClick} のように書いてコンポーネントにそのメソッドを書く、引数にイベントを取れるので色々可能。テキストボックスの入力値も value={this.state.inputValue}のようにしてstateの中に持ち、値のリセットなんかもsetState経由でstateを操作して行う…という流れ。

 その後はコンポーネント生成→破棄までのライフサイクルメソッドを一通り。このへんもVue.jsと似ています。全体的にこの4章を読むとReactの基本部分の実例がかなりイメージが湧くかと思います。

第5章:Reduxでアプリケーションの状態を管理しよう

 よく話を聞く状態管理のRedux。前章のToDoアプリと同じことをReduxを使って作り直す形で進んでいきます。

  • npm install --save redux でインストール。
  • Reducerを定義。Todo追加のアクションが飛んできたらtasks配列に追加してstateを返すような関数。
  • ActionCreatorを定義。Todo追加のアクションでActionオブジェクトを返すような処理をアロー関数で定義、変数に入れておく。テストがしやすくなる。
  • 状態を集約管理するStoreを定義。Reduxが定義しているcreateStorek関数でオブジェクトを生成する。dispatchなどメソッドが用意されているので必要に応じ使う。
  • 4章のTodoアプリと組み合わせていく。最初は1ファイルの中に全て書いているので、ディレクトリ構成を components/, actions/, reducers/ と分けていく。

 ここまで自力でやって骨が折れるので、続いてはReactとReduxを組み合わせる部分を手助けしてくれるReact専用ライブラリの react-reduxの話。

  • npm install --save react-reduxでインストール。
  • <Provider>機能。Reactエレメントをrenderしていく時にアプリ側タグを囲む最上位のタグを <Provider store={store}>に変えて管理。長い親子関係をずっと下にたどって行かなくても、状態集約管理のStoreを任意のコンポーネントと紐付けることができる。
  • これを実現するのがconnect関数で、4つの引数それぞれが関数を指定する方式で、いろいろ指定。
  • 実際のアプリに組み込む時は containers/ ディレクトリを追加、Reduxと関係したコンポーネントはこちらに置く。

と例が進んでいくのですが、画面と紐付いてイメージしやすいコンポーネントとは離れた関数的なコードの記述ががかなりの量で続き、かなり難しいと感じました。やはりRedux周りでぐんと理解までの壁が高くなりそうです。

第6章:ルーティングを実装しよう

 言語を問わずサーバサイドのWebアプリケーションフレームワークだとほぼ必ず出て来るURLルーティング機能。URLがこれとこれだったらMVCのC層の対応するControllerクラスのこのメソッドを呼ぶ、パラメータはこうやると取れる…というあれですね。
 クライアントサイドのJSフレームワーク(ライブラリ)であるReactではどうするかというと、URL的にどの画面にいるのかをStoreで保持、変化があったらViewの表示内容を変えることで実現とのこと。実装パターンとしては…

  • URL遷移なし:URL関係なくアプリ側に状態を保持して表示を変えていく。しかし画面をリロードしたら最初に戻ってしまうので現実的ではない。
  • URL Hash:URLの最後の#以降の値。元来はページ内リンクに使われていた。#以降が変わっても画面全体の再読み込みはされないので、ここに情報を持って表示を制御していく。
  • history API:ブラウザの戻るボタンで戻るとhistory.back(); になるあれ。今はこのブラウザの履歴情報をAPIで操作できるので、履歴を追加したり履歴移動を検知したりできる。

 Hashと聞くとSHA-256とかで暗号化するパスワードのハッシュ値の方が思い浮かんでしまい、ほえーフロントエンドは進んどるのう〜(老人ムーブ)というカンジなのですが、いろいろあるというルーティングライブラリから2つといいつつ、テンションがアガってきたのか実際には3つが紹介されています。

react-router (2017/12にv4)

 一番メジャー。history APIを使いたい場合は<BrowserRouter>、URLのパスに応じたコンポーネントを出すのは<Route>、#のあとのHashで制御するのが<HashRouter>、SPA内で遷移を簡単にする<Link>、さらに装飾を加えられる<NavLink>など各種APIあり。render()内やJSXのタグ記述内に追記していく。

react-router-redux

 react-routerをさらにreduxに最適化できる。APIはそのまま利用でき、historyオブジェクトを強化してStoreが管理しているstateに同期させてくれる。

redux-first-router

 react-router-reduxと同じくルーティング情報はStoreのstateに持つ方式。URLの変化とStoreに持っているルーティング情報が双方向でバインディングされる。

 説明とかコード例がいろいろ載っているのですが、高度すぎて正直分かりませんでした(笑)  ほぼシングルページアプリケーションを作る際にしか出てこない話ですが、最前線はすごいもんだという所。

第7章:Redux Middleware

 Reduxは状態管理の軽量なアーキテクチャ・ライブラリなので、機能を拡張してくれる仕組みであるMiddlewareがあり、世界の様々な人が公開中。各ミドルウェアは互いに影響を及ぼさないように作られており、ふつうにnpmでインストール可能。ということでミドルウェアを紹介しています。

  • ReduxのActionのログを出してくれるredux-logger。様々な設定が可能。
  • 実際にMiddlewareを作る例。アロー関数が3つ並んだ「resultを返す関数を返す関数を返す関数」JavaScriptコードで定義する。すごい。
  • 非同期処理を実現するredux-thunks
  • HTML5で追加されたlocalStorageを使い、stateを保存してみるMiddlewareの例。

第8章:Reduxの非同期処理

 プログラム言語を問わず厄介なところでもある非同期処理。本書ではReduxを使ったアプリケーションでサーバのAPIと通信して返ってきたレスポンスをアクションとして処理したいが、その前にメソッドを抜けちゃう…という状況で7章のredux-thunksを使った方法、またredux-thunksの他の機能を説明しています。

第9章:UIをきれいにしよう

 Redux近辺の高度な話がいったん終わり、今度はReactで画面の見た目をスタイリングしていく話。

  • JSXのstyle属性は文字列でなく、JavaScriptオブジェクトを書く。連想配列で一気に指定できる。
  • style属性で書いていく効率の良い方法はOSSライブラリの CSS-in-JSというものもある。
  • class属性の代わりのclassName属性で書いていく方が一般的。外部CSS<link rel=〜で読み込む普通の方法の他にも、JavaScriptの中でimport './xx.css'のように書き、webpackなどを組み合わせてインポートする手法もある。
  • React向けのUIライブラリも幾つかある。
    • Material-UI: Googleマテリアルデザイン用。
    • React-Bootstrap: その名の通りBootstrapのReact版。
    • Rreact Desktop: Electronプラットフォームなど、デスクトップアプリ用。
    • Onsen UI: ネイティブっぽいモバイルWebアプリ用に特化。

 そして実際の例としては代表的なMaterial-UIを導入した場合が紹介されています。

  • 普通にnpmでインストール。
  • JSコード先頭で import Reboot from 'material-ui/Reboot'のようにnpmで入れたものを指してインポート。
  • JSX記法でタグを書いていく中に最初に <Reboot / ><input type="button">の代わりに <Button ....>のようにタグを入れ替えていく。属性でいろいろオプションが指定できる。<AppBar > などUIコンポーネントは多数。

 他、公式のreact-addons-css-transition-groupを使ったアニメーション実装など。

第10章:より実践的なアプリケーションを作ろう

 素人には既にもう十分複雑だったのですが(笑)、ToDoアプリでは物足りないのでもっと複雑で実物に近いアプリケーションを作ろう…という章。YahooのランキングAPIを通し、人気商品をカテゴリー別に表示するアプリケーションを作っています。
 雛形ディレクトリをcreate-react-appで作り、redux周りとreact-router周りも入れ、サーバーとの非同期通信はreact-reduxを使い、動くようになったらMaterial-UIも導入…とかなり本格的なアプリケーションです。

第11章:アプリケーションのテストを書こう

 単体テストのテスティング・フレームワークの章。
 Reactの場合は、Facebookが開発したテストフレームワーク Jestが標準でcreate-react-appにも標準搭載。Node.jsで動きます。__test__ ディレクトリか名前が *.test.js, *.spec.jsのファイルが対象、npm test コマンドで全実行される形です。関数名が toBeTruthy() だったり、RubyRSpecに似ていますね。
 またReduxを導入したアプリケーションだと純粋な関数が多くなるため、テストが容易になるとのこと。ライブラリ類は以下を紹介しています。

  • redux-mock-store: redux-thunkなどを入れた非同期処理で、Storeをモック化してくれる
  • jest-fetch-mock: サーバ側のAPIをモック化してくれる
  • enzyme: 仮想レンダラーでReactコンポーネント側のテスト用。関連ライブラリと一緒に入れて、各イベントをシミュレートしてテストコードで判定できる
  • react-test-renderer: コンポーネントレンダリング結果をスナップショットで保存。テスト時に前回と比較して差がないかチェックしてくれる。画像ではなくてレンダリングされたHTML文字列の比較をしている模様。

 さすがに周辺エコシステムが豊富なReact、テスト周辺ライブラリもいろいろあってnpmでどんどん入れていくんだなという印象です。

第12章:作ったアプリケーションを公開しよう

作ったらインターネットに公開しようという章。

  • GitHub Pages: GitHub の、登録リポジトリの特定ブランチをWebサイトとして公開できる機能。
  • Firebase: Googleが買収したmBasS(mobile Backend as a Service)、モバイル向けのバックエンドサービスを提供している。ここのFirebase Hostingを使ってアプリを公開できる。GitHub Pagesより高機能。

第13章:サーバサイドレンダリング

 ソシャゲなどのSSレアのSSRと紛らわしいSSR:Server Side Redering 。JSフレームワークはクライアントサイドで動くのにサーバサイドとはなんやねんと思っていたのですが、やっと理解できました。
 ReactやVue.js、AngularでSPA的なアプリケーションを作ると究極的には画面のHTMLタグ部分は.jsやその他の形式のコンポーネント内に全部消えて隠れ、メイン画面のHTMLのBODYタグ内は一番外側の <div id="app"></div>だけになったりします。
 最初の通信のHTTPレスポンスでJSソース一式と寂しいHTMLがサーバから返され、JSが全部ロードされてJSフレームワークが動き、コンポーネントが生成されてその子とその子が作られて画面の寂しいdivタグの中がどんどん増えて描画され、本来の画面ができあがる。
なのでネットワークの速度が遅かったりすると最初の寂しい真っ白な画面が表示されたままの時間が伸びてしまうので、これをなんとかしよう…というのがサーバサイドレンダリング。ゲームでNow Loading...の待ち画面を工夫するようなものでしょうか。(ゲーム脳)

 サーバへの負荷が高まること、アプリケーションがさらに複雑になることは明言されており、その上で効果があると判断した時だけに行った方がよい…としています。簡単な流れは以下。

  1. サーバサイドでリクエストを受けると、DBやロジックから必要データを収集。
  2. ReactはReactエレメントからHTMLに変換する機能を持っているので、HTMLに変換。
  3. この初期表示HTMLをシリアライズして、埋め込んでレスポンスとして送信。
  4. クライアントサイドでレスポンス受信、表示用HTMLでコンテンツを描画して表示。
  5. その後クライアントサイドでJSが動いて本物のReactが動く。

 Rect v15までとReact Fiberを使うv16からで方法が違うとのことで、それぞれの実装方法を解説しています。最近時々名前を聞く、サーバサイドのレンダリングなどを提供するReact用のフレームワーク Next.js の話は出てきません。
 サーバサイドが基本の身からすると、そんなことまでするのか…! 最初からSomeController@indexメソッドでHTMLテンプレートを普通に返して初期表示するだけじゃダメなの? という感想も持ちましたが、ネイティブアプリっぽい見た目のReactアプリとかだとそうもいかないんでしょうね。実装方法の方はほとんど理解できなかったのですが、これはもう新しい世界でした。
 あとクライアント/サーバのNode.js側どちらでも動作するコードをIsomorphic JavaScript、もしくは広い動作環境を意識したコードをUniversal JavaScriptと呼ぶそうです。

気になったところ

★1章からもうReduxの話が出てきますが、内容がぐんと難しくなるのは「第5章:Reduxでアプリケーションの状態を管理しよう」からなので、ここからでも良かったのではと思いました。

★前半はしっかりJSXやコンポーネントの話をして手堅く積み上げていくのですが、7章のMiddlewareの話でミドルウェアの紹介とサンプル作成がごっちゃになっていたり、後半になるとやや散漫な感じもします。章によって執筆者の方の文章のテンションが若干上下もしています。

★タイトルに「入門」とありますが実際にはかなり本格派の仕事向けなので、まったくReact初めての方には若干敷居が高いかもしれません。JavaScript周辺の情報を他の本やWebで集めてからのほうが良いと思います。また、JavaScriptの言語自体を学んでいる途中の方にも本書は厳しいので、もっと易しい本で勉強してからの方ががよいでしょう。
 まあ入門とあるけど入門レベルよりもっと高度だったというのは、技術書に割とありがちですね。

まとめ:2018年時点のReact v16最新情報と仕事レベルの開発がしっかり学べる本

 npmでインストールする関連ライブラリもかなりの量の名前が登場し、JavaScriptとReact周辺のエコシステムについても概要を把握できます。基礎に留めている他の小さな入門本だと出てこないこともあるReduxやURLルーティング、UIの改善やテストやサーバサイドレンダリングなどなど、本格的な開発に必要な周辺情報が一式揃った最新の本です。ビジネスユースのプロダクトでのReact開発で日本語のがっつりした書籍を1冊読むならまず本書でしょう。

 かくいうフロントエンド初心者の僕は後半部分は1回では理解しきれなかったのですが(笑)、Reduxによる状態管理のあたりからちゃんと再読して理解しないとなーと思いました。Material-UIでの見た目改善とかSSRとか沢山のライブラリなどなど、完全に新しい世界のイメージが湧いたのは素人にも収穫でした。

 なお、2018/3/23発売の『React開発 現場の教科書』も本書と同じくビジネスユース向けのしっかりした本。最新でかつ仕事向けの本は現状この2冊になりそうです。関連書籍は別エントリにてまとめようと思います。

React開発 現場の教科書

React開発 現場の教科書