./ChildArea.jsx
import { memo } from "react";
const style = {
width: "100%",
height: "200px",
backgroundColor: "khaki"
};
// memo()でコンポーネント自体(アロー関数)を囲うことで、propsが変更されない限り再レンダリングさせないことができる
export const ChildArea = memo((props) => {
const { open, onClickClose } = props;
const data = [...Array(2000).keys()];
// 2000件の配列をループで回してコンソールログを出力する(ChildAreaコンポーネントのレンダリングの度に走る重い処理)
data.forEach(() => {
console.log("...");
});
console.log("ChildAreaがレンダリングされた!");
return (
<>
{open ? (
<div style={style}>
<p>子コンポーネント</p>
<button onClick={onClickClose}>閉じる</button>
</div>
) : null}
</>
);
});
import { useState, useCallback, useMemo } from "react";
import { ChildArea } from "../ChildArea";
import "./styles.css";
export default function App() {
console.log("App");
const [text, setText] = useState("");
const [open, setOpen] = useState(false);
const onChangeText = (e) => setText(e.target.value);
const onClickOpen = () => setOpen(!open);
/** 関数の処理が変わらない場合は、同じものを使い回させたいのでuseCallBackで囲ってあげる
* useCallBackは第一引数に関数、第二引数に依存配列を受け取る
* 第二引数に空配列を指定すると、初回レンダリングに生成された関数を使い回す
* 第二引数に変数を指定すると、その変数に変更があった場合のみ関数を再生成する
*/
const onClickClose = useCallback(() => setOpen(false), [setOpen]);
const temp = useMemo(() => 1 + 3, []);
console.log(temp);
return (
<div className="App">
<input value={text} onChange={onChangeText} />
<br />
<br />
<button onClick={onClickOpen}>表示</button>
// <子コンポーネントのPropsにアロー関数を渡す時、子コンポーネント側で毎回新しい関数を生成していると判断される(関数を普通に渡すだけだと、子コンポーネントをmemo化していてもPropsが変更されたと判断されるので子コンポーネントの再レンダリングが走ってしまう)
<ChildArea open={open} onClickClose={onClickClose} />
</div>
);
}
import { useState, useCallback, useMemo } from "react";
import { ChildArea } from "../ChildArea";
import "./styles.css";
export default function App() {
console.log("App");
const [text, setText] = useState("");
const [open, setOpen] = useState(false);
const onChangeText = (e) => setText(e.target.value);
const onClickOpen = () => setOpen(!open);
const onClickClose = useCallback(() => setOpen(false), [setOpen]);
/** 変数自体のメモ化をuseMemoで行うことができる
* useMemoは第一引数に関数、第二引数に依存配列を受け取る
* 第二引数に空配列を指定すると、初回レンダリングに生成された変数を使い回す
* 第二引数に変数を指定すると、その変数に変更があった場合のみ変数を再生成する
*/
const temp = useMemo(() => 1 + 3, []);
console.log(temp);
return (
<div className="App">
<input value={text} onChange={onChangeText} />
<br />
<br />
<button onClick={onClickOpen}>表示</button>
<ChildArea open={open} onClickClose={onClickClose} />
</div>
);
}
基本的に、複数の要素から成り立っているコンポーネントや、今後肥大化が予想されるコンポーネントはmemo()で囲ってあげる。
関数の処理が変わらない場合は、同じものを使い回させたいので関数全体をuseCallBackで囲ってあげる。
Propsに関数を受け取るコンポーネントの再レンダリングを最適化する場合は、コンポーネントのmemo化と関数定義にuseCallBackを設定することをセットとする。
変数自体のメモ化をuseMemoで行うことができる。
そこまで使う機会はないが、変数に設定する中の処理が複雑になっている時などのケースでは有効である。