React Hooks （メモ化のフック）

## 概要
React Hooks メモ化のフックについてまとめました。

## メモ化とは
ある関数の呼び出し結果を保持し、同一の呼び出し毎の再計算を防ぐ手法
Reactにおいて、必要のない子要素のレンダリングや再計算を防ぐ為に使用する。

### ■useCallback
関数をメモ化するためのフック

比較のためにNomalとNoneCallbackコンポーネントを用意。
上記コンポーネントはそれぞれParentの再描画が行われるたびに再描画される。
Callbackに渡すonClickはuseCallbackでラップし、
第1引数に関数、第2引数に依存配列を設定する。
useCallback()は関数の再描画の度に依存配列の値を比較し、
前回の描画時と同じ場合、メモ化している関数を返す為
空の配列の場合毎回同じになるので再描画は発生しない。
```tsx
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と同じく、依存配列を比較して関数の再実行を制御する。
```tsx
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
```