October 7, 2016

好みのjs frontほにゃららを探して1

仕事はECのプラットフォームの作成なので、やっぱりWEB。そうするとReact+Flux/ReduxやらAngularやらの話はやっぱり敏感になるのだけれど、多くの人と同様に「これは未来だ!」と感動したり、躓いては「これはなんか違う」って思ってる。 色々試してみて、全部に共通してると感じたのはコンポーネントを作ってパーツ化して再利用しやすくするということ。これは大賛成。 でもまだやっぱりしっくりこないなあと思っているので原因を考えてみる。

一番しっくりきたのはRiot.js

React+Flux/Redux, Angular2, WebComponents+Polymer, Riot.jsを試してみて一番しっくりきたのはRiot.jsだった。WebComponents+Polymerもよかったけど、少し遅いしまだ早いと思った。もしこれがブラウザネイティブになるなら喜んで使うけど。 React+Flux/Reduxは初めて試したときはとても感動した。Reduxなんかとくに。Pureな関数だけを実装することで状態を制御して、それゆえに見通しが良くなるのがすごくいい。 ただやっぱりJSXはなれなかった。 Angular2はすべてががっちり固まってるのがつかれる。Reactと違ってテンプレート使えるのは受け入れやすかったけど。

そこでRiot.js。Riot.jsは軽量だし、WebComponentsをいい感じに実現できるしVirtualDOMで今っぽくてよかった。

Riot.jsでカスタムタグを作るとこんな感じ。

<custom-tag>
  <h1 onclick={changeMsg}>{message}</h1>

  <script>
    this.message = "Hello, World!";
    this.changeMsg = function(){
      this.message = "Hello, Riot.js";
      this.update();
    }
  </script>
</custom-tag>

Riot.js最高って考えてた時期もありました。

そう。最高って思ってた。でも次のいくつか問題にあたってからは「おしいなあ」って気持ちしかない。

  • カスタムタグのネストがつらい
  • 他のJSライブライリとの相性の悪さ
  • ifの値falseでもレンダリングが走る

まず、カスタムタグのネストがつらいと感じた。できるんだけどおしい。例えば次のようなにHTMLをかいてレンダリングすることを考えてみる。

<custom-tag1>
  <custom-tag2>
    <custom-tag3/>
  </custom-tag2>
</custom-tag1>
<script>
  riot.render('*');
</script>

この書き方自体はうまくいくし描画もされるのだけれど、custom-tag3は3回描画されます。 ちなみにcustom-tag2は2回、custom-tag1は1回です。それぞれ1回ずつ描画されることを期待しますけどそうじゃないんですよね。 これはriot.render('*')が良くないとも言えますが、まあそこは掘り下げず、3回呼ばれるとまずい場合があるのかということから。

ネスト回数分だけレンダリングが走ってしまうと、AJAXなどで外部からデータをロードするようなタグがこまる。ネスト回数分おんなじリクエスト飛ばすんかい!?ってなっちゃう。(そんなタグを作るでない!とも言える)

2つ目の他のJSライブライリとの相性の悪さってのも1つ目のやつに起因しているのだけれど、何回も初期化コードが走ってほしくないものがある。例えば、エディタ系。 monaco-editorをタグ化したのだけれど、monaco-editorはDOMを内部で生成するからネスト回数分エディターが作られちゃう。

3つ目は、次のようなコードをレンダリングさせたとき、custom2の方もレンダリング処理が走るということ。もちろん、custom2のif条件はfalseなので描画はされないが、custom-tagのレンダリング処理は実行されるので、無駄な処理が走る。

<custom-tag id="custom1" if={true} />
<custom-tag id="custom2" if={false} />

つまり、Riot.jsは今はあまりネストしないほうがいいし、ajaxするようなコードは書かないほうがいいし、DOMが生成される既存の外部ライブラリを含めないほうがいいし、もちろん思い処理は含めないほうがいい。 でもこれってしたいよね。特にajaxとか。指定のJSONをロードするselect-boxとか作りたいじゃん?

Ajaxコールって関数じゃなくてやっぱりオブジェクトだよね。

fetchとか$.ajaxとか使いやすいし、今までなんとなくこっちのほうが、XMLHttpRequstよりもあるべき姿と漠然と思ってた。だけど、やっぱり通信って状態から縁を切れないよね。そうするとreduxみたいにmiddlewareの中に押し込むのどうなんだろう?って感じた。

じゃあリクエストをストアにためるのはどうかというと、状態を自己改変するからreduxだと扱えない(扱うべきでない)のかなと。そしたらやっぱりmiddlewareに落ち着くよね。

もう文章グダグダだけど

そんなこんなで、しっくりくる実装を今日も考えてる。

© iwate 2016