👻

Jotaiのdependency trackingは何がすごいか

2023/07/05に公開

Jotaiについてツイートしたら、dependency trackingがどうrender optimizationと関係するかについて聞かれました。

https://twitter.com/younguyen95/status/1676084154973450240

ブログ記事にしようかと思いつつ、ひとまず、ツイートで返信しようと思うも文字数が足りない。そこで、Excalidrawで書いて、Shareable Linkにしました。

https://excalidraw.com/#json=JIVmON3SLwmfaDfeTLV1l,aJ2W0m9eD6fkie9N92zcJg

ついでに、画像も貼り付けました。

image

意訳

ZustandとかReduxではグローバルステートにおけるレンダリングの最適化をselectorを使って行います。しかし、selectorはReactのrender phaseで実行され、新しいオブジェクトを生成すると別物と扱い無駄なレンダリングが発生してしまいます(これを解決するためにreselectやproxy-memoizeなどのライブラリが存在します)。そこで、Proxyを使った最適化をReact-Trackedで実現しました(ちなみにこれはusage trackingと呼んでいます)。のちに、これをベースにValtioが誕生しました。Proxyを使った最適化は挙動が多少マジカルなため好まれない場合があります。そこで、atomベースのステートで最適化しようとしたのがJotaiです。アイデアとしては新しくなく、Recoilだけでなく、observable系の仕組みで昔から実現されていたものです。atomベースのステートの場合はdependecy trackingにより、selectorのようにrender phaseで実行する必要がなく無駄なレンダリングが発生しません。

何がすごいか

タイトルにした何がすごいかですが、何もすごくないというか、Proxyベースの最適化と比べると依存関係の表現が明示的なことです。

const sumAtom = atom((get) => get(countAtom) + get(anotherCountAtom));

と書いてあれば、sumAtomcountAtomanotherCountAtomに依存していることが明確です。実装としても、get()を記録しているだけで、その先のプロパティアクセスなどは追跡しません。Proxyのような隠れた仕組みを一切使わずに済んでいます。

Dependency trackingはコンパイル時に行うわけではなく実行時に行います。なので、x ? y : zのような動的な表現が可能です。xがtrueの時はyに依存しますが、zには依存しないことになります。基本的な仕組みがシンプルなので、挙動も大抵期待通りになります。

結局、何がすごいかというと、挙動を予測しやすく期待を裏切らないことでしょうか。

おまけ

なぜブログ記事になっていなかったかというと、本の方に書いたからだと後から気づきました。

https://twitter.com/dai_shi/status/1497189869751521282

あと、元のツイートはこちら。JotaiとWeakMapの類似性について。

https://twitter.com/dai_shi/status/1675664173286686720

リンク集

https://github.com/pmndrs/jotai

https://github.com/pmndrs/zustand

https://github.com/dai-shi/react-tracked

https://github.com/pmndrs/valtio

https://github.com/dai-shi/proxy-memoize

Jotai Friends

Discussion