Hooks と Composition API の比較記事を読んだが自分の理解力が低すぎて理解しきれなかったのでまた読むことを決めた
React HooksとVue Composition APIの比較
読んだ。
読んだ結果、自分はいかに React / Vue のエアプユーザーだったのかというのがよく分かった。
正直一度読んだだけでは頭に入ってない部分もあるので、また読む。
結論にあるとおりのことを学んだ。
React Hooks
Reactでは子コンポーネントの不要な再レンダリングを避けるために使用者側がuseMemoやuseCallbackを使用してオブジェクトをメモ化することで子コンポーネントに渡すpropsの同一性を維持し、パフォーマンス問題を防ぐ必要があります(子コンポーネントはReact.memoで覆う必要性があります)。
この際、メモ化関数の依存配列に適切な値をいれなければ、古い状態を参照してしまうStale Closureという問題があります。これはJavaScriptでは関数が作成されたタイミングでクロージャが作成されるので、関数作成時のレキシカルスコープ内に存在する変数を保持する事が原因です。
ここらへん非常に自分の理解が曖昧ということが分かった。
クロージャは関数とその関数が作られた環境という 2 つのものの組み合わせです。この環境は、クロージャが作られた時点でスコープ内部にあったあらゆる変数によって構成されています。
関数を定義して、それをプログラムが実行して関数を生成したときにクロージャが作成される。クロージャが作成されるということは、中で使われている変数がその関数外で定義されていたとしても環境そのものを保存するという感じになるので保持してしまう。
ここらへんだけでも理解が浅かった。
Composition API
Hooksと違い、Composition APIではコンポーネントのインスタンス生成時に一度だけsetup()関数を呼び出します。これによってHooksのStale Closureの様な問題は起きません。また、Hooksの様に条件分岐内で呼び出してはいけないといった制約もありません。
リアクテビティを実現するためには先ほどtrack関数によって格納されたeffectを呼び出す必要がありますが、この関数を実行する役割はtriggerEffectという関数が担っています。つまり、状態をリアクティブに保つには状態を呼び出すタイミングでtrack関数を、状態が更新されたタイミングでtriggerEffect関数を呼び出せば良いということです。
状態の呼び出し・更新に応じてtrackやtriggerEffectを呼び出すには、ProxyというES6から導入された機能によって実現する事ができます。
なるほど(しか言えないくらい理解が浅かった)
結論
Hooksでは状態をイミュータブルに保つことを強制し、専用のsetter関数を提供しましたが、Composition APIでは値をrefやreactiveで覆うことで状態をミュータブルに更新するこができました。その結果ReactではuseMemoやuseCallbackで計算をメモ化しましたが、Composition APIではweakMapやProxyを用いることでライブラリ側で効率的に依存関係を更新することができました。
どうにもまだ完全に理解しきれておらず引用まみれになってしまう。
ちょっとこの記事はもう一回読みます。自分の理解力の低さが憎い。
記事自体は Hooks や Composition API が出てきた歴史やその当時の問題、状態管理の基礎的な知識などがとても丁寧に説明されていて本当に素晴らしいと思いました。自分もこういう記事が書けるようになりたい。