概要
React Hooks メモ化のフックについてまとめました。
メモ化とは
ある関数の呼び出し結果を保持し、同一の呼び出し毎の再計算を防ぐ手法
Reactにおいて、必要のない子要素のレンダリングや再計算を防ぐ為に使用する。
■useCallback
関数をメモ化するためのフック
比較のためにNomalとNoneCallbackコンポーネントを用意。
上記コンポーネントはそれぞれParentの再描画が行われるたびに再描画される。
Callbackに渡すonClickはuseCallbackでラップし、
第1引数に関数、第2引数に依存配列を設定する。
useCallback()は関数の再描画の度に依存配列の値を比較し、
前回の描画時と同じ場合、メモ化している関数を返す為
空の配列の場合毎回同じになるので再描画は発生しない。
import React, { useState, useCallback } from 'react'
type ButtonProps = {
onClick: () => void
}
// こちらは通常の関数コンポーネント
const Nomal = (props: ButtonProps) => {
const { onClick } = props
console.log('nomal再描画されました')
return <button onClick={onClick}>nomal</button>
}
// こちらはメモ化した関数コンポーネント
const NoneCallback = React.memo((props: ButtonProps) => {
const { onClick } = props
console.log('noneCallback再描画されました')
return <button onClick={onClick}>noneCallback</button>
})
// こちらはメモ化した関数コンポーネント
const Callback = React.memo((props: ButtonProps) => {
const { onClick } = props
console.log('callback再描画されました')
return <button onClick={onClick}>callback</button>
})
export const Parent = () => {
const [count, setCount] = useState(0)
const nomal = () => {
setCount((c) => c + 1)
}
const noneCallback = () => {
setCount((c) => c + 1)
}
// useCallbackで関数をメモ化
const callback = useCallback(() => {
setCount((c) => c + 1)
}, [])
return (
<>
<p>Count: {count}</p>
{/* コンポーネントに普通の関数を渡す */}
<Nomal onClick={nomal} />
{/* メモ化コンポーネントに普通の関数を渡す */}
<NoneCallback onClick={noneCallback} />
{/* メモ化コンポーネントにメモ化した関数を渡す */}
<Callback onClick={callback} />
</>
)
}
export default Parent
■useMemo
値をメモ化するためのフック
第1引数に値を生成する関数、第2引数に依存配列を設定する。
useCallbackと同じく、依存配列を比較して関数の再実行を制御する。
import React, { useState, useMemo } from 'react'
export const UseMemoSample = () => {
// テキストボックスの中身を保持
const [text, setText] = useState('')
// 文字列のリストを保持
const [items, setItems] = useState<string[]>([])
const onChangeInput = (e: React.ChangeEvent<HTMLInputElement>) => {
setText(e.target.value)
}
const onClickButton = () => {
setItems((prevItems) => {
// 現在の入力値をitemsに追加、配列を作成して保存する
return [...prevItems, text]
})
// テキストボックスを空にする
setText('')
}
const numberOfCharacters1 = items.reduce((sub, item) => sub + item, '')
// useMemo使用、itemsが新しくなった時だけ関数を実行する
const numberOfCharacters2 = useMemo(() => {
return items.reduce((sub, item) => sub + item, '')
}, [items])
return (
<>
<p>SampleUseMemo</p>
<div>
<input value={text} onChange={onChangeInput} />
<button onClick={onClickButton}>Add</button>
</div>
<div>
{items.map((item, index) => (
<p key={index}>{item}</p>
))}
</div>
<div>
<p>Combining Characters 1: {numberOfCharacters1}</p>
<p>Combining Characters 2: {numberOfCharacters2}</p>
</div>
</>
)
}
export default UseMemoSample