Reactのライフサイクルマネジメント学習
こちらの記事をもとに始める
まずはクラスコンポーネントのライフサイクル。
以下に記事からのスクショ
マウントは初期描画時に相当する。DOMがrenderされてブラウザに描画反映されている。外からのデータはcomponentDidMountでロードする仕様。
その後、propsやstateに更新があった場合に画面を更新するのが"更新" (update)。
次に関数コンポーネント (function component)のライフサイクル
以下、同様にスクショ
クラスコンポーネントと比較して、
effect部分が componentDidMount / componentDidUpdate相当なんだね、と。
あと、記事でも言及されているが関数コンポーネントではマウント時にも更新時にも同様にinitializeが走る。
クラスコンポーネントでは更新時にはrender + componentDidUpdateしか走らなかった。
つまり、関数コンポーネントでは
stateやpropsが変わった場合にもinitializeされる。
ということ。
だからマウント、更新の度に関数コンポーネントに書かれた全てが実行されてしまうんだな。
これが巷で関数が実行されることが「レンダリング」と呼ばれていることの理由だったわけだ!
それを避けるためにはメモ化して関数の実行そのものを防ぐ必要がある。
うむ、理解した
紹介されているこちらの記事を読む
Note: If you are familiar with React Class Components, you may have noticed that a Functional Component is a React Component without render function. Everything defined in the function's body is the render function which returns JSX in the end.
つまりfunctional componentはrender functionの中に詰め込んでいるんだと。
だからマウント時も更新時も頭から全て実行される。
useMemo
useEffectと同様に実行するコールバック関数とその依存配列を引数にとります(useEffect について知りたい方はこちらを見てください)。第二引数の依存配列の値が変更された場合のみ、値の再計算がされます。なお依存配列が渡されなかった場合は、レンダリング毎に新しい値が計算されてしまします。
そしてuseMemoはレンダー中に実行されるため、副作用などの処理はuseEffectにさせ、レンダリングに関係する処理のみを行いましょう。
非常にコストのかかる計算を行う場合に使用してください。あまりコストのかからない計算をメモ化すると値を再計算するか判定する処理の方がコストがかかる場合があります。
useCallback
useCallBackは、メモ化されたコールバック関数を返します。メモ化とは同じ入力が再度発生した時に、キャッシュした結果を返すことです。
useCallbackの第一引数にはuseEffectと同様にコールバック関数を受け取り、第二引数も同様に依存配列を受けます。依存配列にセットされた値のいずれかが変化した場合のみ useCallback の戻り値が再計算されます。
React はレンダリング毎にコンポーネント内の関数は別の関数に変わるため、useEffectの依存配列に関数を用いると、レンダリング毎に useEffect に渡したコールバック関数が呼ばれてしまうことになります。
=> useCallbackを使ってメモ化することによりレンダリングごとに関数のメモリ参照が変更されないようにして無駄にuseEffectが呼ばれないように出来る
React.memoと組み合わせた場合
(React.memoは)新しく渡された props と前の props を比較して、等価であれば再レンダリングを行わずにメモ化したコンポーネントを再利用します。
なので、この props に関数を入れる場合、useCallbackでメモ化した関数を使うとメモ化されたコンポーネントを再利用でき、最適化しやすくなります。
useEffect
useEffect の定義
第一引数には副作用の処理を記述するためのコールバック関数を持ち、これはレンダーの結果が画面に反映された後に動作します。
第二引数には依存先の変数が格納される配列が渡されます。これによって副作用の処理をどのタイミングで実行するか決めることができます。
まず、第二引数を指定しない場合は、副作用は全レンダリング後に実行されます。
第二引数を指定した場合、配列に格納された値が変更された場合のみ実行されます。
第二引数に空配列が渡された場合、副作用は最初のレンダリングが行われた後だけ 1 回実行されます。
副作用の中には、タイマー ID や subscription など、コンポーネントがアンマウントされる時にクリーンアップする必要があります。そのような時にuseEffect内で関数を返すことでそれをクリーンアップの処理とみなすことができます。
useEffect内のcallbackのreturnにcleanup callbackをセットできるということ
useState
useEffect使うかどうかについて考える前にuseStateについておさらい
コンポーネントがレンダリングされる度にuseStateが実行されます。この時、state を初期化する計算にコストがかかる場合、毎回この計算を行っているとパフォーマンスに支障がでる可能性があります。
そこでuseStateの引数に関数を渡すことで初期レンダリング時に 1 度だけ初期化の計算を実行させることができます。そのため、2 回目以降のレンダリングでは初期化する処理は呼び出されず、コストのかかる計算はスキップされます。
useEffectについて追加でこちらに書いた