reactのmemoが使いこなせない...
【助けていただいたサイト一覧】
- 公式様
- react.memoの解説がとても分かり易かったです
出発の問題
前提: react.memoの仕様の把握
react.memoを使ってパフォーマンスアップするぞーと意気込んでいました。
作業内容は、あるデータをループで回してリスト化する。あるあるです。
このデータはしょっちゅう変更されますが、
// 前回データ
[0:{title: 'わに'},
1:{title: 'とり'},
2:{title: 'いるか'}
]
// 変更後データ
[0:{title: 'わに'},
1:{title: 'かば'},
2:{title: 'やぎ'}
]
であった場合、0個目のリストのpropsは変わらないので、再レンダリングするのはエコではありません。
コードで示すと以下のようになります。
parent.js
Parent = () => {
const [stateTest, setTest] = useState({
array: [
{title: 'わに'},
{title: 'とり'},
{title: 'いるか'}
]
})
const propsChanger = () => {
setTest({
array: [
{title: 'わに'},
{title: 'かば'},
{title: 'やぎ'}
]
})
}
let ListDom = []
stateTest.array.forEach((item, i) => {
ListDom.push(
<List objData={item} key={`list${i}`}/>
)
return (
<div>
{ListDom}
<div onClick={propsChanger}>props更新!</div>
</div>
)
}
List.js
export default function List ({objData}) {
console.log(`${objData.title}はレンダリング`)
return(
<p>{objData.title}</p>
)
}
再レンダリングさせない...react.memo
の出番だ!と思ったわけです。
import React, { memo } from 'react'
const List = memo(({objData}) => {
console.log(`${objData.title}はレンダリング`)
return(
<p>{objData.title}</p>
)
})
export default List
メモをかませたので、shallowで比較されるはず、、!
と思って更新ボタンを押すと、
わに、しっかり再レンダリングされていました...
なぜ?
オブジェクトの比較はインスタンスが違うと中身が同じでも同等と見なされないから。
memoを使いこなすのは難しそうです。
解決方法!
その1 オブジェクト・配列は渡さない。
Parent
stateTest.array.forEach((item, i) => {
ListDom.push(
<List title={item.title} key={`list${i}`}/>
)
})
List
const List = memo(({title}) => {
console.log(`${title}はレンダリング`)
return(
<p>{title}</p>
)
})
export default List
propsを文字列で渡すようにしました。これであれば わにのリストは再レンダリングされませんでした。
でも、渡す情報が多い場合は、propsをたくさん渡さなければなりません。
その2 第二引数を使う
deepな比較はshallowよりコストが高いので注意です!