直前の記事に続いて、子供コンポーネントに関数propsを追加して渡せば、どのような状況になるでしょ
import React, { useCallback } from 'react'
import CommentItem from './CommentItem'
export default function Comments({commentList}) {
// onClickイベントハンドラー関数
const handleChange1 = (() => {
console.log("push");
});
return (
<div>
{commentList.map(comment => <CommentItem
key={comment.id}
title={comment.title}
content={comment.content}
likes={comment.likes}
onClick={handleChange}
/>
)}
</div>
)
}
Comments.jsxのCommentItem propsに固定のonClickを設けて、
import React, { Profiler, memo } from 'react'
import './CommentItem.css'
function CommentItem({title, content, likes, onClick}) {
function onRenderCallback(
id,
phase,
actualDuration,
baseDuration,
startTime,
commitTime,
interactions
) {
// レンダリング度にログを出力する!
console.log(`actualDuration(${title}: ${actualDuration})`);
}
const handleClick = () => {
onClick();
}
return (
<Profiler id="CommentItem" onRender={onRenderCallback}>
<div className="CommentItem" onClick={handleClick}>
<span>{title}</span>
<br />
<span>{content}</span>
<br />
<span>{likes}</span>
</div>
</Profiler>
)
}
export default memo(CommentItem); // memoはHOC!
CommentItemのeventHandlerに追加して、memoizationが効くのかを検証!
結果は以下。
結果からわかるように、前回のレンダ結果を再使用せず、また最初からレンダリングした結果を出しています。
その理由としては、Memoizationの時にreactはpropsを比較して再使用するかを決めています。
上記では、Commentsに関数のpropsを新しく追加したので、reactは前Propsと現Propsを比較し、違うものと判断して
再レンダリングしちゃいます。
(shallow compare : 基本タイプデータの場合、値が同一かどうかだけを比較。
オブジェクトの場合は、参照だけを比較する。値が同じでも、参照値が異なるため、再レンドリンが発生する。)
この場合に使用できるのが{ useCallback } HOOKです。
useCallbackは関数(Object)をmemoizationしてくれます。
useCallbackは、関数を保存するhookです。reactに関数を保存し、実行ごとに再生成しないようにします。
メモリ内の同一の場所のいずれかに保存されるため、同一の関数(オブジェクト)であるか比較することができます!
import React, { useCallback } from 'react'
// (・・・省略)
//修正前
const handleChange1 = (() => {
console.log("push");
});
//修正後
const handleChange = useCallback(() => {
console.log("push");
}, []);
10個のコンポーネントが作成された時点のログです。
useCallbackを使う前とは違く、ちゃんと前回の結果が再使用されていることがわかります。