UGA Boxxx

つぶやきの延長のつもりで、知ったこと思ったこと書いてます

【React】useCallbackの無駄遣い

以前、useCallbackについて調べた

uga-box.hatenablog.com

ただ、このとき

メモ化されたコンポーネント(不必要なレンダーを避けるために参照の同一性を見るよう最適化されたコンポーネント)にコールバックを渡す場合に便利

という部分がよく理解できていなかった

そんなとき、関数オブジェクトの話を聞いて少し理解ができたのでまとめておく

useCallback単体で使っても意味がない

まず、useCallbackの第一引数をインライン関数で定義しておけば、関数定義を省略できるかとういうと、そういうわけではない

useCallbackを使った下のコードは

const onClick = useCallback(function cb() {
    doSomething();
}, [])

だいたいこれと同じになる(cbスコープが変わるので全く一緒じゃない)

const cb = function cb() {
    doSomething();
}
const onClick = useCallback(cb, [])

つまり、関数定義は省略されないし、かつcbは呼び出し毎に関数オブジェクトが作られるのでuseCallback単体で使っても意味がない

というか、むしろ意味ないだけではなく、第二引数の依存リストに変更があるかをチェックする処理がある分無駄な記述ですらある

さらに、useCallbackは2回目に呼び出されたときに第一引数の関数を破棄して、1回目につくられた関数オブジェクトを返すということをしてくれる機能なので、1回目につくられた関数オブジェクトを覚えておくことも無駄ということだった

メモ化されたコンポーネントに渡す

本題の以下の話は

メモ化されたコンポーネント(不必要なレンダーを避けるために参照の同一性を見るよう最適化されたコンポーネント)にコールバックを渡す場合に便利

つまり、useCallback は不要に新しく関数インスタンスを作成することを抑制するので、「メモ化されたコンポーネントに関数を渡す場合に違うpropsと判断されないようにして、不要な再描画を減らしてくれるので便利」ということだと理解した

参考

https://kentcdodds.com/blog/usememo-and-usecallback

https://qiita.com/seya/items/8291f53576097fc1c52a

https://qiita.com/teradonburi/items/5b8f79d26e1b319ac44f#%E3%82%A2%E3%83%AD%E3%83%BC%E9%96%A2%E6%95%B0%E3%82%92props%E3%81%AB%E5%8D%B3%E6%99%82%E9%96%A2%E6%95%B0%E3%81%A7%E6%B8%A1%E3%81%99

https://qiita.com/soarflat/items/b9d3d17b8ab1f5dbfed2