ほぼ Material の TreeView 専用かも
何を解決したいか
以前のReactデモアプリではツリー構造の部署を選択すると部署に所属する社員が表示される際に、ツリーの展開状態は失われてしまう。以下のような感じ。
この状態(改善前)のデモコードは以下のリポジトリから参照することができる
これを改善し、部署選択時にもツリーの展開状態を保持できるようにしたい
コンポーネントの構造と問題の起きる仕組み
デモアプリのコンポーネントは以下のような構造になっている。
部署を選択したときの挙動は以下のようになる
- Folderコンポーネントをクリックして部署を選択すると、propで渡されている
setOrg()
が呼び出される -
setOrg()
は定義元であるAppコンポーネント上で実行され、org
stateが更新される - stateが更新されると、Appコンポーネントは再描画され、子コンポーネントは破棄再作成される
- 再作成されたコンポーネントのstateは初期状態、つまり閉じている状態になる
図にすると以下のようになる
状態のホイスティング(巻き上げ)による解決
これを解決するには、Folderコンポーネントが持っている開閉状態を、破棄されないコンポーネントつまりAppコンポーネントに移譲することで行うことができる。本来のコンポーネントが持つ状態を親に渡すので、状態のホイスティング、巻き上げと呼ぶ。
具体的には以下のようにする
- AppコンポーネントにuseMemoを使って関数
stateStore
を作る。stateStore
の中のプライベート変数に実際の状態が保存される -
stateStore
をpropでFolderまで伝播させる - Folderコンポーネントでは
setState(stateStore.get(パス名))
とすることでstateStore
に保存された値をstateの初期値とする - ツリーが開閉されるたびに
stateStore.set(パス名, 開閉状態)
を呼び出すことで、親コンポーネント内に状態を保存することができる
図にすると以下のようになる
上記を実装したコードは以下の場所で見ることができる(branch: 20250321_hoisted)
修正後の動作は以下のようになる
余談
状態のホイスティング(巻き上げ)は Android JetPack Compose の開発の際に出てくるプログラミングパターンだが、MDNでも言及されている。
理解しているのであればMDNの解説でもわからなくもないかもしれないけど、全く知らない人は読んでも何がいいのかよくわからないと思う。
おわりです
Jotai使うのでももちろんいいと思う。ちょっとした状態保存なら別のライブラリ使わなくてもできますよってことを言いたかったです。