Posted at

typelessで始めるアプリケーションの状態の分割統治

*こちらは meguro.es # 22 の発表資料になります



自己紹介

株式会社オプト シニアエンジニア @sisisin(しめにゃん)


  • GitHub

  • Twitter

  • フロントエンドの人と見せかけてスクラムマスター・インフラ・サーバーサイドといろいろやります

  • 今はAWS/Rails/Reactなプロダクトのテックリードやりつつ社内アジャイル相談窓口とかやってます

  • typelessオタクなので語らせるとやかましいです


どのぐらいオタクかというと、


このぐらい

ss_ 2019-08-08 3.33.33.png



この発表の想定対象者


  • reduxの設計に頭を悩ませたことがある

  • Reactのhooks APIを知っている



typelessとは


  • redux+redux-observableライクに状態管理が出来るライブラリ

  • TypeScriptフレンドリーに作られていて、型注釈なしで自然と型安全性を維持したコードになる

  • hooksを使って非常に手軽にStateの取得やActionの発火をしやすい仕組みを提供している

  • 個人の所感としてはリッチでスケール可能なReact.useReducerみたいなもの

以前書いた紹介記事: typelessというReact向け状態管理ライブラリがめっちゃいい



今日伝えたいこと


  • typelessでは独立したStoreの構築を前提としたAPIを提供している

  • それとは逆に、StoreとComponentを密結合にするような設計をしやすくもなっている

  • この組み合わせによって、振る舞いと見た目を1セットとしたComponentを構築しやすくなる


    • 言い換えると、「Reduxに持たせたくないがためにComponentのstateとして持たせて振る舞いを定義していた複雑な処理を状態管理ライブラリ側に寄せることが出来る」とも言える




*「Store」の指す意味について

ここではStoreを「発行されるActionをリッスンしており、Actionに応じてReducerを適用して新しいStateを作る機能」とする


  • Redux,NgRx,Vuexで利用されているStoreがそのまま該当する想定

  • typelessの場合、reducerだけでなくepicという副作用処理をする処理も走るなど、ここで言うStoreと多少振る舞いが異なるが、便宜上Storeという単語で、Store相当の機能について話すことにする



typelessでは独立したStoreの構築を前提としたAPIを提供している


  • Storeの「発行されたActionに対してReducerを適用して新しいStateを作る」という振る舞いを実装者の任意のタイミングで有効・無効の制御が可能となっている

  • React hooksとして有効化関数が提供されている



    • useHogeModule() のように実行すれば有効化

    • 上記コンポーネントがアンマウントされれば無効化





typelessでは独立したStoreの構築を前提としたAPIを提供している

(図)

たとえば aReducer , bReducer があったとして aReducerのみが有効化されていればどんなActionが起こっても bReducerは何もしない



これにより享受できるメリット


  • Storeは分割統治が前提となり、必要なときに必要なだけのアプリケーションの振る舞いを記述できる

  • 全てのActionが常に全てのReducerを通り、誰がどのActionに対して状態を更新するのか?ということに気を払う必要がなくなる


    • Reduxでは全てのReducerが任意のActionに対しての振る舞いを記述できるため、制御が困難になりうる

    • そういった問題を避けることが出来る





StoreとComponentを密結合にするような設計をしやすくもなっている

先程の説明で述べた「React hooksとして有効化関数が提供されている」ことによってこれが実現されている

つまり、「特定のComponentは特定のStoreとセットである」ということを以下のように記述できる

const HogeModule = () => {

useHogeModule();
return <HogeView />
};



これにより享受できるメリット


  • Componentと実質密結合なロジックを1つの塊として定義しておける

  • 例えば、「SPAで各エンドポイントごとのRootComponentに対応する1つのStore」、という表現が非常にやりやすい


    • これ自体はReduxでもconnect噛ませたComponentがそうだよね、という話はありつつ





この組み合わせによって、振る舞いと見た目を1セットとしたComponentを構築しやすくなる


  • typelessでは独立したStoreの構築を前提としたAPIを提供している

  • StoreとComponentを密結合にするような設計をしやすくもなっている

という2つの特徴の組み合わせにより、振る舞いと見た目を1セットとしたComponentを構築しやすくなる



これにより享受できるメリット


  • Reduxに持たせたくないがためにComponentのstateとして持たせて振る舞いを定義していた複雑な処理を状態管理ライブラリ側に寄せることが出来る(再掲)

  • StoreとComponentが密結合なロジックをtypeless側で書くことで取り回しやすさやリファクタしやすさが段違いに良い

「ちょっと複雑な振る舞いを持った小粒なComponent」を非常に手軽に表現ができることがとても良い



この設計がそこそこハマった事例があるので紹介



蔵書管理アプリ

リポジトリ: https://github.com/opt-tech/bibliotheca-pwa

これなに?


  • 会社で管理してる書籍の貸し借りを管理するアプリ

  • 例えば書籍のバーコードをカメラから読み取って、「借りる」「返す」事が可能

  • 管理用機能としてバーコードから読み取った書籍の「登録」も可能

  • などなど



デモ



蔵書管理アプリ

この「書籍のバーコードをカメラで読み取る」部分をStoreとComponent1セットで BarcodeLoaderModule として表現している

https://github.com/opt-tech/bibliotheca-pwa/blob/master/packages/front/src/bibliotheca/features/barcodeLoader/module.tsx#L47



BarcodeLoaderModuleのやっていること


  • デバイスがカメラを利用できるか判定

  • ボタン押下でカメラを有効化

  • バーコードを取得したら、payloadにバーコードの数字を持つ emitBarcode Actionを発火

例えば登録画面なら、 emitBarcode を受け取って書籍情報を獲得し、フォームに書籍情報を埋める。

貸し借り画面なら、 emitBarcode を受け取って書籍情報を獲得し、貸し借り対象となる本を確認出来るようにする

といった実装ができる



終わりに

というわけで「typelessで始めるアプリケーションの状態の分割統治」でした

ここで紹介した以外にも非常に優れた点を多数持っているので、気になった方は是非使ってみてください



Happy Hacking!