非SPAのWebアプリケーションで局所的にSPAを適用する際のポイント

[システムエンジニア Advent Calendar 2016](http://qiita.com/advent-calendar/2016/se)の16日目の記事です！
昨日は@garbagetownさんの[基本/詳細設計って呼び方やめませんか](http://qiita.com/garbagetown/items/a3ae46595f7c49e587a0)でした！

# はじめに
jspを使ったWebアプリケーションのあるページ間だけサクサクっと動かしたいという要件があり、局所的にSPAを導入しました。
その時に考慮したポイントや漏れていたポイントを反省しつつまとめてみました。 

# ポイント
ポイントとしては以下があげられます。
1. 技術選定
2. SPA内での状態管理
3. 値をサーバーにPOSTするタイミング
4. ブラウザバック

## 1. 技術選定
まずはSPAフレームワークについて、[TECHNOLOGY LADER](https://www.thoughtworks.com/radar/languages-and-frameworks)でトレンドをみてみると以下のフレームワークがとりあげられています。

- Ember.js
- React.js
- Aurelia
- vue.js
- Elm
- Angular.js (HOLD?!)

最初の画面から完了画面まですべてSPAで完結するような大規模に使う場合は、上にあげたフレームワークを使うのはありだと思います。しかし、一部のページ間をシュッと切り替えるだけのライトな使い方をする場合はややオーバースペックで学習コストがかかってしまう印象です。

プロジェクトの状況にもよりますが、携わった案件では以下の観点を重要視していた為、無理してSPAフレームワークを使わずjQueryでやろうという方針になりました。

- 新規参入者の学習コストがかからない
- 広く一般的に使われている技術
- ドキュメントがしっかりしている
- シュッと切り替えるだけだから

結果、jQueryにしたことで割とシンプルにつくれたと思っています。

以下の記事ではjQueryとSPAフレームワークの使いわけについて考察されていて参考になります。
[JavascriptのSPA(Single Page Application)フレームワークの使いどころ（jQueryとの比較）](http://qiita.com/sjuny/items/3b2bfc7762aaae52b887)

## 2. SPA内での状態管理
jQueryにしてもSPAフレームワークにしてもUIの状態管理の方法を考えなければ複雑で大変な作業になってしまいます。
どこのどいつが状態を書き換えているかのか管理せずに、なんでもかんでも値を詰めてしまうとシステムが複雑になってしまいます。

そこで、状態管理の方法としてreduxという選択をしました。
reduxの説明はここではしませんが、[TECHNOLOGY LADER](https://www.thoughtworks.com/radar/languages-and-frameworks)でも`ADOPT`に指定されている状態管理の為のフレームワークです。
reactに限らずreduxは他のSPAフレームワークとの組み合わせも可能です。
（例えば、vue.jsでは[revue.js](https://github.com/revue/revue)というライブラリを使ってreduxと連携できるようになります）

「え、reduxも聞いたことあるけど、どうせ明日には消える技術なんじゃ」と思うかもしれませんが、reactなしでも使えるので個人的にはここは押さえておいてもいい技術のような気がします。
今回jQueryとreduxを組み合わせて使いましたが、これもシンプルに使うことができました。

## 3. POSTするタイミング
SPA内で値をPOSTするタイミングは大きく分けて２つが考えられます。
1. 各画面のボタンクリック時にajaxでPOST
2. 最後のページでまとめてPOST

**各画面のボタンクリック時にajaxでPOSTする場合**
この場合はサーバーとの非同期通信がその都度発生するので、エラーハンドリングのことを考えなくてはなりません。
例えばシュッと画面は切り替わっちゃったけど、エラーが返ってきてあわわわ。ってならないようにしなければなりません。
結果が帰るまで、画面を切り替えないようにするか、エラーメッセージを表示するモーダルを出して、SPAの最初のページに戻すなどの処理が必要となります。

**最後のページでまとめてPOSTする場合**
この場合は途中入力してきた状態を復元させることが難しいです。リストから選択していく遷移方法であればRESTfulなシステムで用いられる一意的な（ユニークな）URIを使って復元が可能ですが、氏名や生年月日などの入力フォームを保持させるにはstorageやcookieを使って保持する仕組みが必要かと思われます。
POSTする前の入力途中の値の復元はしない方針に懇願した方がいいのが個人的な意見です。

## 4. ブラウザバック
ここでいうブラウザバックはページ遷移後（jspが変わった後）にブラウザバックされた時の話です。その際の注意点が２つありました。
1. ルーターで定義したURLに戻れるようにする
2. 状態の復元

**ルーターで定義したURLに戻れるようにする**
ルータで定義したURLはあくまでjsよってフロント側で定義されたURLなためWEBサーバーからは見つけることができません。何も考えずブラウザバックをすると、404(not fount)になってしまいます。
その為、apacheならばrewriteを使ってURLをWEBサーバーから見つかるURLに変えてあげる必要があります。

**状態の復元**
ここは私の考慮が漏れていたポイントで、反省しています。
jspが変わってからブラウザバックした場合、当たり前ですがreduxで管理していた状態（storeの中身）が消えてしまっています。
ブラウザバックして表示されるページはSPA内の最後のページになると思いますが、その際にstoreの中身が完全に元に戻っているようにする必要がありました。
`local storage`を使うことも考えましたが、復元したい項目が少なかったので`input hidden`を駆使して実現しました。

ブラウザバックではhistoryを壊さないように注意することも必要で、
そのことは@yosuke_furukawaさんが最近書かれたブログにもあります。
[リクルートテクノロジーズのフロントエンド開発 2016 - from scratch](http://yosuke-furukawa.hatenablog.com/entry/2016/12/01/175446)


# まとめ
1. 技術選定  
私はSPAときいてすぐにフレームワークを考えてしまいましたが、jQueryでも問題なく実現できました。
プロジェクトの要件とスキルに合わせて、最適なものを選びましょう。
2. SPA内での状態管理  
状態管理が煩雑になるとあとあと大変な思いをするので、reduxを取り入れてみてはどうでしょうか。
3. 値をサーバーにPOSTするタイミング  
プロジェクトの要件に合わせて採用すれば良いかと思いますが、POSTするタイミングによってできることとできないことが発生するので、そのことを事前に説明してシンプルに実装できるようにしたいですね。
4. ブラウザバック  
次ページへの遷移によってSPAで保持していた状態がリフレッシュされるので、ブラウザバックでSPA内に戻った際にはstoreを復元することを考えてあげる必要がありました。

今回書いた内容は全て試したわけではないので、考慮が足りていない部分があるかもしれません。
ご指摘があればよろしくお願いします。
みなさまの参考になれば幸いです。

「jQueryを使うのは恥だが役に立つ」ってタイトルにすればよかったかな？

明日は@backpaper0@githubさんです！うぇーい！٩( ´ω` )و