Reactでのメモ化の方針
useMemo
計算に1msかかるならuseMemo
↓古いmrsekut.icon
古いというのは、mrsekut.iconの中の考えとして古いだけで、React側でなにか変化があったわけではない
ちょっと考えが変わっている
書き直すモチベが今はないので放置している
リンク先だけ参考にして、このページの内容はあまり参考にしないほうがいいかも
Reactの以下のようなメモ化処理を何も考えずにしまくったときに起きる弊害を考える
こういう思考になってしまう
defaultでmemoれば良いじゃん
じゃあ全部React.memoすればよくね?
useMemoとuseCallbackはデフォルトで良いじゃん?
これが、そうでもないんだよなー、という反論
useMemo, useCallbackに第二引数を書かない
depsにその場で生成したオブジェクトを入れる ref 冗長になっているだけ
適切でない値をdepsに入れているので意図通りの挙動にならない
結論
「メモ化した値との比較処理」v.s.「メモ化せずに新しく生成するなど」の対立構造になる
厳密に見るためには、いちいち検証が必要
そんなことはやってられないので勘と妥協でどうにかする
単純にdepsの数が増えるほど比較コストが上がる ref 実装の該当場所
useMemo
値の計算コスト v.s. メモ化比較
その値を作る計算が複雑になるほどコストは上がる
ちょっとでもコストがありそうなら使っておけばいい
useCallback
再描画のコスト v.s. メモ化比較
「新しく関数インスタンスを生成」するところというよりも。
なので、子に参照を渡さないのであれば使う意味はない
逆に、子に渡すなら使っておけばいい
関数インスタンスを作成するコストは先ほどの is関数の比較するコストよりおそらく低いでしょうref 個人的には直感に反するmrsekut.icon
検証してみたい
例えば、コンポーネント生成時に一回作ったらそれを使えば良い状況でも子に渡さなかったら無意味になるの?
第2引数がuseCallback(fn, [])となる状況のとき
特にコンポーネントがform等の場合は、人文字入力するごと(?)に、その関数が再生成されることになる
その中身は全く変わらないにもかかわらずだ
React.memoを使わないほうが良い場合ってどういう時?
第2引数を省略した場合、shallow equal比較なのでネストが深いコンポーネントを渡している場合は、意図せず再描画されなくなる 具体例を見たいmrsekut.icon
頻繁に変わりうるpropsを複数受け取るコンポーネントの場合は比較コストのほうが大きくなる
つまり、比較関数がほぼ常にfalseを返すような状況
第二引数を省略しても、省略しなかったとしても
useCallbackを使わずに、親で定義されたmethodが渡ってきた場合も無意味なので、比較コストだけがかかる感じになる
無意味なのは、関数オブジェクトは生成するたびに異なるものになるから
code:ts
const sumFactory = () => {
return (a, b) => a + b;
}
const sum1 = sumFactory();
const sum2 = sumFactory();
console.log(sum1 === sum2); // => false
バグの発生しやすさ
useMemoやuseCallbackを使うと、相対的にバグが出る可能性は上がる
もちろん何も考えずにdepsを書いている時の話
逆にあえてバグらそうと思ったらどうすればいい #?? 関連
useStateの再描画はバッチ処理される
参考
計測して1ms以上かかるならuseMemoを使う
useCalback, useMemoについて
内部実装のコールドリーディングなど
setCount(count + 1)ではなくsetCount(prev => prev + 1)と書こうという話