「Harajuku.ts Meetup 〜 Recoilの事例集めました〜」参加メモ

ナレッジワークのよしこさんが登壇するというのを会社のtimesで知ったため、イベント内容をメモしながら聴きました。
よしこさんの発表が終わった直後に電話がかかってきてしまったため、okunoさんとna2hiroさんの発表はメモが少なめになっています。

イベントページ

私はYouTubeライブで参加しました。
以下メモです。

イベント趣旨のご説明

  • Recoilはリリースして2年半経っているが、事例があまり出てこない

  • Twitterでつぶやいたところ、登壇者が集まってくれた

  • どのように使っている/いないかの発表をしてくれる

  • ハッシュタグ #harajuku_ts

登壇

「ステート管理を超えるRecoil運用の考え方」@uhyo_

  • 事前アンケート結果の共有

    • Jotaiもかなり似たライブラリなので、脳内変換しながらお聞きください

    • 差異に個人的に興味があります

  • 自己紹介

    • 22年10月からバベル勤務

    • ブルーベリー本の著者

  • 話すこと

    • aileadフロントエンドにReactとともにRecoilを使用。なぜ、どうやったのか

    • 2つ

      • 実はFlixって天才だったのでは

      • Recoilくんとならやり直せる気がする

実はFlixって天才だったのでは

  • ReactはUI構築以外の仕事をさせない方がいいのでは

    • UI以外のことの例、外部からのデータの読み込みとか

  • 理想的なアーキテクチャ、Reactにはレンダリングしてもらって、外部からのデータ読み込みとかは外にやってもらったほうがいいのでは?と思った

  • この図、Fluxと似ている

    • FluxだとStoreとなっているところが、コア層と整形層に分離した

    • 単純なFluxだと成果物が「でかい状態の塊」になるのが辛い

  • Recoilの運用アイデア

    • コア層と整形層をやってもらう

Recoilくんとならやり直せる気がする

  • Recoilのいいところ

    • atomとselectorがあり、コアな状態がどれなのかを設計上明らかにしやすい

    • 非同期ネイティブであり、非常期処理もselectorとして扱える

  • 思想がReact本体と近い「ロジック用のReact」のような使い心地

  • atomとselectorの使い分けがだいじ

    • 他に従属しない状態がatom

    • それ以外は何が何でもselector

  • Recoil層とReact層の境界は当然フック

  • 具体例の説明

  • ReactにUI以外のことを無理にやらせると、アプリケーションの整合性を保つのが困難になる

    • 検索条件が変わったのに検索結果が前のままという中途半端な状態がレンダリングされてしまう

    • Recoil内部で整合線の取れた状態を計算し、終わってからReactに

  • ReactとRecoilの整合性保証、似ている部分がある

    • React:状態→画面の整合性

    • Recoil:グラフ→状態の整合性

  • 整合性の棲み分け

  • Recoilを活用するデータフロー設計

    • シンプル・ローレベルなAPIから構成されている

    • 望ましい設計を保ちやすい

    • 具体例

まとめ

  • Recoilをロジックに用いる設計を試している

  • 改めて見てみると、Fluxの良いところを受け継ぎ良くないところを直したような構成になっている

  • ReactはそろそろUIライブラリに専念させてあげたい

  • 文章で読みたいかたはこちら


ナレッジワークでのState管理とRecoil活用事例@yoshiko_pg

(公開されたらスライドを貼る。)

自己紹介

  • よしこ

  • 株式会社ナレッジワークのフロントエンドエンジニア

  • GUIをSPAとして作るのが好き

  • 自社での技術スタックや設計をZennで公開しています

  • 下記のStateについての記事をじっくり深ぼる

話すこと

  • 前提:SPAにおける3種類のState

    • ナレッジワークでどうStateを管理しているのか

  • Recoilを使ったGlobal State運用ルール

    • Recoilをどう運用しているか

  • Recoilを使ったGlobal Stateの変更フロー

前提:SPAにおける3種類のState

  • Stateは結構フロントエンド開発において難しいことの一つ

  • 変化しうるデータが「状態」としてある色々な「状態」がある。

    • 全部の状態をSingle Stateに入れていた感じの設計もあったかもしれない

  • 分解してみると、こういう状態がある

    • 「Componentを超えて共有する必要のある状態:Global State」と「特定の状態に閉じた状態:Local State」

      • Componentを超えて共有する必要のある状態:Global State

        • Componentは、Root Componentは例外として、それ以外の任意のComponentを指している

        • 「超えて」は、自分を超えて、他のComponentだったり、自分自身へもunmountされてライフサイクル超えたときとか

          • 閉じた状態ならuseStateとかすればいいが、そこを超える必要が出てくると、もっと永続した状態が長いところ、Root Componentにも出せる

        • ここで言っているGlobal Stateは、言い換えるとRoot ComponentのLocal Stateとも言えるかもしれない

          • URLやLocal Storageなどの永続する値は含んでいません

      • 特定の状態に閉じた状態:Local State

  • もう一段階ブレイクダウンした

    • 「Componentを超えて共有する必要のある状態:Global State」をブレイクダウン

      • Global Stateに置かなければいけないデータって何だろう

        • 大体はサーバーデータのキャッシュでは?

      • 従来のGlobal Stateからサーバーデータのキャッシュを除くと、残るデータはわずか

      • であればそれらは必要最低限の仕組みでそれぞれに管理すればよいのでは?

    • ということで、こう

      • 状態

        • Componentを超えて共有する必要のある状態

          • サーバーデータのキャッシュ:①Server Data cache

          • それ以外:②Global State

        • Componentに閉じた状態:③Local State

      • 上記の②Global StateでRecoilを使っている

Recoilを使ったGlobal State運用ルール

  • 前提

    • 今回紹介するナレッジワークでのRecoilの使い方は、ピュアなGlobal Stateとしてのかなりシンプルな使い方になる。

    • APIも9割方atomしか使っていない。

    • 前段でStateを3つに分類したことでGlobal Stateの担う役割が最小限になり、最大限シンプルな使い方でもニーズを十分カバーできるようになった。

  • Recoilを使ったGlobal State運用ルール

    • ①置き場所・命名のルール

      • src/globalStates以下に1Stateあたり1ファイルを作成する

        • RecoilはStateたくさん作れる。使いたい状態ごとに1ファイル作っている

      • ファイル名はxxxState.ts

        • ファイル名単体で見た時も役割が明確

      • ファイル名をRecoilのKeyにする

        • Recoilは、ファイル名が衝突するとエラーになる

        • ファイル名をそのままkeyにすることで、Global Stateの中に同じ名前のファイルを入れることができないため、keyが衝突しないことを担保できる。頑張らなくても済む仕組み。

    • ②露出させるインターフェイスのルール

      • StateそのものやsetStateなどRecoilのAPIを直接露出させず、React用/Write用のカスタムフックひとつずつのみ露出させる

        • ライブラリの知識を隠蔽できる。腐敗防止層にもなる

          • サーバーからしたら何のライブラリで管理しているのかは知らなくても良い情報

          • 今後Global State管理ライブラリを乗り換えたくなったときも、このGlobal StateレイヤーのファイルとRoot ComponentのProviderだけ書き換えればOKになる

          • ライブラリを隠蔽するのはナレッジワーク内で他にも使っている箇所がある。一層噛ませて吸収できるようにしておくのはおすすめ

        • (主にWriteで)操作に「意味」を持たせる

          • useStateを提供してしまうと、操作の意味や文脈が使う側に委ねられてしまう

          • 「このStateはこういう操作ができる」をState側に提供させ、使い方を限定させる

      • Read hookのルール

        • StateのRead hookはuse 〇〇Stateの命名規則でexport

          • 大体useRecoilValueをラップしているだけ

          • toastStateをサンプルにしている

        • 任意のComponent/Usecaseから利用可能

      • Write hookのルール

        • State のWrite hookはuse〇〇Mutatosとしてexportする

          • setStateをラップしたWrite関数のまとまりを返す。setStateは直接露出させない。行いたい操作ごとに専用の関数を提供することで、このStateはどんな操作を想定しているのか?も伝えることができる

          • Write関数を必ずメモ化する(使う側でdepsに入れることを想定)

        • 任意のUsecaseから利用可能

      • Callback hookのルール

        • ほとんどないが、ちょっとだけある

        • 知りたい人はuhyoさんのブログ読もう

Recoilを使ったGlobal Stateの変更フロー

  • これで伝わるかな

    • ユーザーがクリック

    • Componentがクリックをハンドリング

    • Usecaseというレイヤーを設けており、そのUsecaseをComponentが呼び出す

    • Global Stateの書き込みは、Usecaseのレイヤーからだけ許可することにしてデータフローの方向性を保っているので、Usecaseから書き込みをする

    • Global Stateの値が変わったら、それをSubscribeしているComponentが自動で再レンダリングされる

  • Usecaseの記事、去年の大晦日に公開したので是非読んで

おやくそく

We’re Hiring!!!


『それでもどうしてRecoilを使うのか』@okunokentaro

  • Recoilが出番となるとき

    • Propsバケツリレーがあまりにも頻繁で生産性・可読性ともに低下を実感するとき

    • React Contextの出番になりそうな全ページ全コンポーネントで共有する情報があるとき

  • 積極的Recoilも消極的Recoilもアリ

(電話に出ていたため、メモが少ない)

Recoilと将棋ったー@na2hiro

(電話に出ていたため、メモを取っていない)

感想

  • かなり断片的な感想だが、Recoilを使ったGlobal State運用ルールの「Recoilはファイル名が衝突するとエラーになるため、ファイル名をそのままRecoilのKeyにすることで、keyが衝突しないことを担保できる」という部分、「人が頑張ってしっかりすること」に依存せずに「うっかりを仕組みで防いでいく」に寄せていく感じいいなと思った

  • フロントエンドエンジニアではないため難しいと感じる部分もあったが、それも含めていい刺激になってよかった。YouTube LIVEなので、もし配信が残るならokunoさんとna2hiroさんの発表も観てみよう


この記事が気に入ったらサポートをしてみませんか?