トップ «前の日記(2018-05-03) 最新 次の日記(2018-05-07)» 編集

2018-05-06 [長年日記]

_ ViewModel ComponentにModelを通じて世界の覗き窓を作る

先日来 JavaScript の ViewModel 系フレームワークで監視対象外のデータをどう扱うかというところに注目しているのだけど、これには理由があって、

  • VM Component の単位で影響を閉じ込めるという発想はGood
  • 単方向のデータバインディング、データフローもGood
  • VM Component が UI を司るのでどうしても VM Component が Model を mount するという形になり、かつモダン JS の世界では Rails 的にすべての Model が global に展開されるという考え方は NG
  • VM Component のどこかに Model を mount しつつ「すべてのデータを監視対象とするわけではない」という形が扱いやすそう
    • Angular で Change Detection を打ち消しまくろうとするアプローチは「気にしたくないものを網羅する」という形になるので現実的な感じがしない(まず漏れると思う)

ということで MobX にたどり着いたわけだ(Vuex Store が State 前提すぎるので)。ただし、MobX ですべて解決とは思っていなくて、自分の感覚としては

  1. VM Component が世界のすべてを知っている必要はない(むしろユーザーとのインタラクションと直接関係しないロジックで世界は満ちている)
  2. Component の外の世界はいきなり HTTP とは限定できない
  3. Component を司る Parent Component で Model を通じた外の世界の覗き窓を提供する

くらいの感じがいいのかなと思っている。

Modelを管理するModelからParent ComponentがChild Componentに世界の覗き窓を教えてあげる関係図

いったんのイメージとしては図のような感じ。

ここでロジックとして「掌握する世界がより広い」のは Model > VM Component であり、Parent Component > Child Component である。

Parent Component の初期化の際に(Vue + MobX なら fromMobx のような方法を通じて) Model を持ち、さらにこの Parent Component が Child Component を生成する際にも(例えば v-for などの記述の際に)Parent Model の「機能」や「State 相当の data」を props で渡してあげるようにすることで、より広い「世界」に対する「覗き窓」を手に入れるという具合である。

「覗き窓」というのが肝心なところで、props で渡されたものを監視しないのは無理だし、Child Component の責務は基本的には Model への直接の介入ではなく Parent Component への Event Bubbling に留めた方がよいという判断。

本当は Child Component からうまく Model の一部の機能にタッチすることができた方が便利だなと思っていたんだけど、それをやるにはやはり独自の名前空間を切って plugin として Vue Component に inject してやらないと無理っぽいので、いったんは「覗き窓」の部分だけを明文化しておこうと思った次第。

今回の話は特に目新しい話もなければ包括的な設計指針でもない。そういう話は メンテナンスしやすいVueComponentを設計するために気をつけていること などを読むとよい。

ちなみに上で言っている Parent と Child というのは React を参考にしつつ用語を整理していくとどうも

Container か否か

という切り方をするっぽい。

ここで言い方を変えると Container が Coponent 生成時に Model から覗き窓を props で渡す という感じか。

なるほどなるほど。

順番が前後したが、なぜわざわざこれを書き起こしているかということを整理しておしまいにしようと思う。

React 以降の VirtualDOM 前提の ViewModel フレームワークはあくまで VirtualDOM というごく限定的な世界のことをうまく扱うように特化しており、ViewModel フレームワークの強い制約はその中で破綻しないようにするためにはよい工夫ではあるが、ユーザーとのインタラクションは生DOM や Window, Canvas など VirtualDOM ではどうしようもない部分も含んでいるし、Model 自体は ViewModel Framework の制約とは独立して考えてよいというか独立して考えるべき、そうでないとどうしても無理が出ると言ってよいと思う。

極端な話、ViewModel Framework は Model の全体像など知らなくてよい「あくまで VirtualDOM へマップしやすい情報だけを扱っているのだ」くらいの認識にしておかないと Model 設計の際に VM Component の制約で頭が固まりそうで怖いな、と感じたので、選択肢を作り*1、それを文字に起こしておくことにした。

あとはねぇ、Rails の ActiveDecorator みたいなことをやれれば Model はさらにすっきりするんだけどねぇ…。Model に View 向けの変換が入っていると邪魔だし、かと言って Component で持つと似た記述があちこちに散らばるし、mixin を使えばできなくはないんだけど、Model をどう Component 内に持つかは Component 次第なので mixin で解決しきるのはとても厳しいわけですよ。ね。

参考

Getterの辺りに異論はあるのですが、よくまとまっていて非常に参考になります。

*1 監視しないデータとロジックの置き場所を確保すること