React-useEffect, useLayoutEffect, useMemo, useCallback, useReducerの使い方

# 理解のポイントと前提
1. 描画サイクルの理解
Reactアプリケーションは「データの更新⇨コンポーネントの再描画⇨その他の処理」の一連のサイクルを繰り返す
2. 「その他の処理」の実装方法
useEffect, useLayoutEffect, useMemo, useCallback, useReducerを使う
3. 描画関数の実態は関数である
3. 「依存配列」という仕組みを使うことで、「その他の処理」の実行タイミングを細かく定義できる
3. return文を書くことで、描画コンポーネントがアンマウントされた時の処理を定義できる(useEffect, useLayouEffect)
3. useEffectとuseLayoutEffectは仲間
3. useMemoとuseCallbackは仲間

## useEffect関数
Reactコンポーネントの描画が完了した**後に**実行される関数
```react
export default function App() {
	const [val1, setVal1] = useState("");
	const [val2, setVal2] = useState("");

	// 描画完了後ごとに実行される
	useEffect(() => {
	  console.log("first render");
	});
	
	// 初回描画完了後に実行される
	useEffect(() => {
	  console.log("first render");
	},[]);

	// 初回描画完了後に実行と
	// またはAppコンポーネントがアンマウントされた時returnで返した関数が実行される
	useEffect(() => {
	  console.log("first render");
	  return console.log('unmounted component');
	},[]);

	// 初回描画完了後と
	// val1の値が変化したら実行される	
	useEffect(() => {
	  console.log(val1);
	},[val1]);
  
	// 初回描画完了後と
	// val2の値が変化したら実行される
	useEffect(() => {
	  console.log(val2);
	},[val2]);
  
	return (
	  <>
	  {/* 省略 */}
	  </>
	);
  }
```
### 補足
1. 第一引数にコンポーネント描画後に実行される関数を渡す。
1. 第二引数に依存するステート値を配列で渡す。第二引数に渡す配列を依存配列という。
1. 空の依存配列を渡すと、コンポーネントの初期描画時のみ第一引数で渡した関数が実行される。
1. 第二引数は省略可能。省略すると、描画完了後ごとに実行される。

## useLayoutEffect関数
使い方はuseEffectと同じ。コンポーネントの描画がされる**前に**実行される。

## useMemo関数
第二引数にフックしたい値を依存配列として渡し、渡した変数が変化したら第一引数の関数が実行される。依存配列を使ってフックしたい値を第二引数に定義するのでuseEffect, useLayoutEffectと似ている。
ではなぜuseMemo関数があるのかというと、依存配列に渡された値が同一かどうか（つまり変化していないかどうか）のチェックには二種類あり、場合によってはuseEffect, useLayoutEffectが意図しない動作になることがあるからである。以下Javascriptの仕様である。
```javascript
// プリミティブ値の場合=文字列,真偽値,数値の場合
const val1 = 'apple'
const val2 = 'apple'
const boo1 = true
const boo2 = true

// 参照値の場合=オブジェクト,配列,関数の場合
const array1 = ['hoge', 'huga', 'piyo']
const array2 = ['hoge', 'huga', 'piyo']
const fun1 = () => console.log('hoge')
const fun2 = () => console.log('hoge')

// プリミティブ値の場合は値が同一であるかどうかで評価される
console.log(val1 == val2) // true
console.log(boo1 == boo2) // true
// 参照値の場合はインスタンスが同一であるかどうかで評価される
console.log(array1 == array2) // false
console.log(fun1 == fun2) // false
```
なので、フックしたい値が参照値(オブジェクト,配列,関数)でかつ参照値をコンポーネント内で生成したい場合は以下のようにする。
```react

// useEffectを使った場合は、意図しない挙動になる
function App({ letter = "" }) {  
	// 例えletterの値が同じでも毎回異なるインスタンスが生成される
	const words = letter.split(" ");

	// なのでletterの値が同じでもconsole.logが実行される
	useEffect(() => {
		console.log("fresh render");
	}, [words]);

	return (
		<>
		{/* 省略 */}
		</>
	);
}

// useMemoを使った場合、wordsには常に同じインスタンスとして代入される
function App({ letter = "" }) {
	// useMemoによるメモ化
	// 第二引数の値が変化したら、第一引数が実行され値はwordsに「キャッシュされる」(同じインスタンスとして)
	const words = useMemo(() => letter.split(" "), [letter]);
  
	useEffect(() => {
	  console.log("fresh render");
	}, [words]);
  
	return (
	  <>
		{/* 省略 */}
	  </>
	);
}
```

## useCallBack
useMemoとよく似ている。useMemoがキャッシュされた「値」を返すのに対して、useCallbackはキャッシュされた「関数」を返す。
```react
function App() {
	// 依存配列が空なので、初回描画時にのみ実行される
	const fn = useCallback(() => {
	  console.log("hello");
	  console.log("world");
	}, []);
	
	// 初回描画時の後に実行される
	// また第二引数のfnが変化したら実行される
	// fnは初回描画時にキャッシュされているので
	// 結果的にfnは不変で、コンソール出力は一度しか実行されない
	useEffect(() => {
	  console.log("fresh render");
	  fn();
	}, [fn]);
  
	return (
		<>
		{/* 省略 */}
		</>
	);
}
```

## useReducer関数
後日書きます。