概要
ここでは不要な再レンダリングを防ぐための技術についてまとめられています。不要な再レンダリングは処理の重さにつながるためできるだけ起こらないように工夫が必要です。
再レンダリングが起きる条件
- Stateの変更が起きたとき
- 新しくPropsが渡されたとき
- 再レンダリングが起きた時の子要素すべて
メモ化とは?
再レンダリングが起こらないようにするための記述です。特に、先ほど挙げた再レンダリングが起きる条件の3つ目である「再レンダリングが起きた時の子要素すべて」はデザインの変更が起きないのに再レンダリングが行われるというとても無駄な処理であるため、メモ化がとても有効です。
メモ化の種類
- コンポーネントのメモ化
- 関数のメモ化
- 変数のメモ化
この3種類です。
コンポーネントのメモ化
export const App=memo(()=>{});
このように、関数をmemo()で囲うだけで親コンポーネントのレンダリングが起きてもapp.jsxはレンダリングされずに済みます。
関数のメモ化
コンポーネントのメモ化は「再レンダリングが起きた時の子要素すべて」が起きることを防ぐためにありましたが、関数のメモ化は「新しくPropsが渡されたとき」に再レンダリングが起きないために用います。
具体例
export const ClickDeleteButton=(props)=>{
return (
<div>
{console.log("clickが再レンダリング")}
<button onClick={props.click}>削除</button>
</div>
)
}
このように関数をpropsで受け取るコンポーネントに対して
import { ColoredMessage } from "./ColoredMessage";
import { useState } from "react";
import { useEffect } from "react";
import { ClickDeleteButton } from "./ClickDeleteButton";
export const App=()=>{
const [num,setNum]=useState(0);
useEffect(()=>{
console.log("ボタンが押されました。")
},[num])
const onClickButton=()=>{
setNum(num+1);
}
const onClickReset=()=>{
setNum(0);
}
return (
<div>
{console.log("appが再レンダリング")}
<button onClick={onClickButton}>ボタン</button>
<p>ボタンが押された回数:{num}</p>
<ColoredMessage color="pink">hello</ColoredMessage>
<ClickDeleteButton click={onClickReset}/>
</div>
)
}
親要素の再レンダリングが起きたとき、関数も新しく生成されるためpropsが新しく渡されたと判断されonClickDelete.jsxの再レンダリングが起きてしまいます。
そこで関数のメモ化とは、
const useCallback((onClickReset=()=>{
setNum(0);
},[])
と記述することで再レンダリングが起きても新たに関数の生成が起きる事態を防ぐことができるため、子要素の再レンダリングが起きません。
まとめ
- exportされるコンポーネントを記述するとき
- 関数をコンポーネントに渡すとき
この2つの場面でメモ化を行うことで処理の負荷を下げることができます。
補足
関数のメモ化と同様に配列やオブジェクトも再レンダリングによって新たに再生成されるため、propsに渡す場合は
const obj=useMemo(()=>{
return {color:"red",message:"hello"}
},[])
こうするこで再レンダリングを防ぐことができる。