REACT HOOK全記録

# REACT Hooksとは何ですか?

:::note warn
警告：記事に機械翻訳があるため、学習メモとして保存、学習参考用のみ
:::


HooksはステータスやライフサイクルメソッドなどのReact機能に「フック」することができます。Hooksは関数コンポーネントがステータスやその他のReact機能にアクセスできるようにします。

### import Hooks from reactが必要です
useState Hookを使ってアプリケーションの状態を追跡します
ステータスとは、追跡すべきアプリケーションデータや属性のことを指します。

### HOOKには3つのルールがあります
```
React関数コンポーネントでのみHooksを呼び出すことができます。
Hooksはコンポーネントのトップレベルでのみ呼び出すことができます。
Hooksは条件付きではいけません
```
### React useState Hook

1.import useState Hookが必要です
```
import { useState } from "react";
```
2.useStateを初期化
```
import { useState } from "react";

function FavoriteColor() {
  const [value, setValue] = useState("");
}
```
最初の値valueは現在の状態です
2つ目のsetValueは状態を更新する関数です
これらの名前は変数であり、任意に名前を付けることができます。
最後に初期状態を空文字列に設定しますuseState("")

3.useStateのデータ保存と追跡
useState Hookは文字列、数字、ブール値、配列、オブジェクト、これらの任意の組み合わせを追跡することができます!

4.useStateのvalueが更新した場合、画面が再レンダリングする
```
import { useState } from "react";
import ReactDOM from "react-dom/client";

function Desk() {
  const [desk, setDesk] = useState({
    brand: "Mitubi",
    model: "Mustang",
    year: "1964",
    color: "white"
  });

  return (
    <>
      <h1>My {desk.brand}</h1>
      <p>
        It is a {desk.color} {desk.model} from {desk.year}.
      </p>
    </>
  )
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Desk />);
```
色だけを更新したい場合は,previousStateを使用して、更新前の値を設定すること
```
 const updateColor = () => {
    setDesk(previousState => {
      return { ...previousState, color: "blue" }
    });
  }
```


### React useEffect Hooks

useEffect Hookではコンポーネント内のSIDE EFFECTを実行することができます。
SIDE EFFECTの例としては、データの取得、DOMの直接更新、タイマーなど。

useEffectは2つのパラメータを受けることができる。2つ目のパラメータは任意
```
useEffect(<function>, <dependency>)
```
1.三つの応用：

```
useEffect(() =>{です
//毎回レンダリング時実行します。
);

```
```
useEffect(() => {
  //最初の一回目のみ実行する
}, []);
```

```
useEffect(() => {
  //最初の一回目のみ実行する
  //そして、propとstateが変更する時実行する
}, [prop, state]);
```

実例として：
```
import { useState, useEffect } from "react";
import ReactDOM from "react-dom/client";

function complement() {
  const [number, setNumber] = useState(0);
  const [counting, setCounting] = useState(0);

  useEffect(() => {
    setCounting(() => number * 2);
  }, [number]); // <- 変数を追加する

  return (
    <>
      <p>number: {number}</p>
      <button onClick={() => setnumber((c) => c + 1)}>+</button>
      <p>counting: {counting}</p>
    </>
  );
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<complement />);
```

2.メモリーのリークを減らすためにClearが必要な場合もあります。
不要になったタイムアウト、サブスクリプション、イベントイレギュラー、その他の効果を解放すべきです。
これでuseEffect Hookの最後に関数を返すことで実現する

```
function Timer() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    let timer = setTimeout(() => {
    setCount((count) => count + 1);
  }, 1000);
  //ここでTimerの解除を行う
  return () => clearTimeout(timer)
  }, []);

  return <h1>I've rendered {count} times!</h1>;
}
```

### React useContext Hook

React Contextは、状態をグローバルに管理する方法です。
useState Hookと一緒に使うことができ、useState単体で使うよりもコンポーネント間で状態を共有しやすくなります。

Contextを作成するには、createContextをインポートして初期化する必要があります。次に、ContextコンポーネントTreeをカプセル化するためにContext Providerを使用します。Context Providerでは、子供compomentに状態値を提供します。

```
import { useState, createContext, useContext } from "react";
import ReactDOM from "react-dom/client";

const UserContext = createContext();

function Component1() {
  const [user, setUser] = useState("TOP Value");

  return (
    <UserContext.Provider value={user}>
      <h1>{`Hello ${user}!`}</h1>
      <Component2 user={user} />
    </UserContext.Provider>
  );
}

function Component2() {
  return (
    <>
      <h1>Component 2</h1>
      <Component3 />
    </>
  );
}

function Component3() {
  const user = useContext(UserContext);

  return (
    <>
      <h1>Component 3</h1>
      <h2>{`Hello ${user} again!`}</h2>
    </>
  );
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Component1 />);


//Hello TOP Value!
//Component 2
//Hello TOP Value again!
```

### React useRef Hook

1.更新時にレンダリングされない可変値を格納することができます。
useRefのcurrentを使って、再レンダリングを避ける
```
function App() {
  const [inputValue, setInputValue] = useState("");
  const count = useRef(0);

  useEffect(() => {
    count.current = count.current + 1;
  });

  return (
    <>
      <input
        type="text"
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
      />
      <h1>Render Count: {count.current}</h1>
    </>
  );
}
```



2.DOM要素に直接アクセスできます
```
import { useRef } from "react";
import ReactDOM from "react-dom/client";

function App() {
  const inputElement = useRef();

  const focusInput = () => {
    inputElement.current.focus();
  };

  return (
    <>
      <input type="text" ref={inputElement} />
      <button onClick={focusInput}>Focus Input</button>
    </>
  );
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
```

3.状態の変化を追跡します
useRef Hookは以前の状態値を追跡するのにも使えます。
```
import { useState, useEffect, useRef } from "react";
import ReactDOM from "react-dom/client";

function App() {
  const [inputValue, setInputValue] = useState("");
  const previousInputValue = useRef("");

  useEffect(() => {
    previousInputValue.current = inputValue;
  }, [inputValue]);

  return (
    <>
      <input
        type="text"
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
      />
      <h2>Current Value: {inputValue}</h2>
      <h2>Previous Value: {previousInputValue.current}</h2>
    </>
  );
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
```
### React useReducer Hook

useReducer HookはuseState Hookと似ている

状態ロジックのカスタマイズが可能です

複雑なロジックに依存した複数の状態を追跡できるようになった場合、useReducerが役立ちます。

```
useReducer(<reducer>, <initialState>)
```

:::note warn
reducer: 現在の状態と動作オブジェクトを受け入れ、新しい状態を返す純粋な関数です。
initialState: 状態の初期値です。
:::


```
import React, { useReducer, useEffect } from 'react';

//function を作成
function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    case 'set':
      return { count: action.payload };
    default:
      throw new Error();
  }
}

function Counter() {
  //useReducer(関数、初期値)
  // state は値、dispatchは関数であること
  const [state, dispatch] = useReducer(reducer, { count: 0 });

//ここで非同期処理
  useEffect(() => {
    async function fetchCount() {
      const response = await fetch('/api/count');
      const result = await response.json();
      
      //reducer関数を実行
      dispatch({ type: 'set', payload: result.count });
    }

    fetchCount();
  }, []);

  return (
    <div>
      <p>Count: {state.count}</p>
      //ここで同期処理
      <button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
    </div>
  );
}

export default Counter;

```

### React useCallback Hook

React useCallback Hookはコールバック関数を返します。useCallbackはuseMemo Hooksに似ています。主な違いは、useMemoはvalueを、useCallbackは関数を返すという点

useCallback は、React の Hook のひとつで、関数コンポーネント内でコールバック関数をメモ化（キャッシュ）するために使用されます。この Hook は、コールバック関数と依存配列を受け取り、依存配列内の値が変化した場合にのみ、コールバック関数を再作成します。

```
const memoizedCallback = useCallback(() => {
  // コールバック関数のロジック
}, [dependencies]);

```

パラメータの説明
callback: メモ化したいコールバック関数。
dependencies: コールバック関数が依存する値を含む配列。これらの値が変化すると、コールバック関数が再作成されます。

例 1: 基本的な使用
```
import React, { useState, useCallback } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  const increment = useCallback(() => {
    setCount((prevCount) => prevCount + 1);
  }, []);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
}

export default Counter;

```
この例では、increment コールバック関数はコンポーネントの初回レンダリング時にのみ作成されます。これは依存配列が空のためです。これにより、毎回レンダリング時に新しい increment 関数が作成されるのを防ぎます。

例 2: 依存配列
```
import React, { useState, useCallback } from 'react';

function Counter() {
  const [count, setCount] = useState(0);
  const [text, setText] = useState('');

  const increment = useCallback(() => {
    setCount((prevCount) => prevCount + 1);
  }, []);

  const handleChange = useCallback((event) => {
    setText(event.target.value);
  }, []);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
      <input type="text" value={text} onChange={handleChange} />
    </div>
  );
}

export default Counter;

```
この例では、increment と handleChange の両方が useCallback によってメモ化されています。これにより、毎回レンダリング時に新しい関数が作成されるのを防ぎます。

例 3.React.memo と一緒に使用
useCallback は、子コンポーネントのレンダリングを最適化するために React.memo と一緒に使用されることがよくあります。
```
import React, { useState, useCallback, memo } from 'react';

const Button = memo(({ onClick, children }) => {
  console.log('Button rendered');
  return <button onClick={onClick}>{children}</button>;
});

function Counter() {
  const [count, setCount] = useState(0);

  const increment = useCallback(() => {
    setCount((prevCount) => prevCount + 1);
  }, []);

  return (
    <div>
      <p>Count: {count}</p>
      <Button onClick={increment}>Increment</Button>
    </div>
  );
}

export default Counter;

```

この例では、Button コンポーネントが React.memo でラップされており、increment 関数が useCallback を使用しているため、increment 関数が変更された場合にのみ Button コンポーネントが再レンダリングされます。

### React useMemo Hook
useMemo は、React の Hook の一つで、特定の値をメモ化（キャッシュ）して、依存する値が変わらない限り再計算を避けるために使用します。計算コストの高い処理の結果や、コンポーネントの再レンダリングの際に再計算を避けたい値をメモ化する際に役立ちます。

```
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
```

パラメータの説明
create: メモ化したい値を生成する関数。通常、この関数内で計算コストの高い処理を行います。
dependencies: 依存配列。この配列内の値が変更された場合にのみ、メモ化された値が再計算されます。

適用シーン
重い計算処理の結果をメモ化し、再レンダリングのたびに再計算を避けたい場合。
子コンポーネントに渡すオブジェクトや配列など、参照が変わると再レンダリングされる可能性がある値をメモ化する場合。

例 1: 重い計算処理のメモ化
```
import React, { useState, useMemo } from 'react';

function ExpensiveCalculationComponent({ a, b }) {
  const memoizedValue = useMemo(() => {
    return computeExpensiveValue(a, b);
  }, [a, b]);

  return <div>Result: {memoizedValue}</div>;
}

function computeExpensiveValue(a, b) {
  console.log('Computing expensive value...');
  // 計算コストの高い処理
  return a + b;
}

export default ExpensiveCalculationComponent;

```

例 2: オブジェクトのメモ化
```
import React, { useState, useMemo } from 'react';
import ChildComponent from './ChildComponent';

function ParentComponent() {
  const [count, setCount] = useState(0);
  const [text, setText] = useState('');

  const memoizedObject = useMemo(() => {
    return { count };
  }, [count]);

  return (
    <div>
      <input value={text} onChange={(e) => setText(e.target.value)} />
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <ChildComponent memoizedObject={memoizedObject} />
    </div>
  );
}

export default ParentComponent;

```
```
import React from 'react';

function ChildComponent({ memoizedObject }) {
  console.log('ChildComponent rendered');
  return <div>Count: {memoizedObject.count}</div>;
}

export default ChildComponent;

```
この例では、memoizedObject は count に基づいてメモ化されています。count が変更された場合にのみ、新しいオブジェクトが生成され、ChildComponent が再レンダリングされます。text が変更された場合、ChildComponent は再レンダリングされません。

useMemo は、計算コストの高い処理や再レンダリングのたびに再計算したくない値をメモ化するために使用します。
依存配列内の値が変更された場合にのみ、メモ化された値が再計算されます。
useMemo を適切に使用することで、パフォーマンスの最適化や不要な再レンダリングを防ぐことができます。






参考資料：https://www.w3schools.com/react/react_hooks.asp