【初心者向け】useStateとuseEffectの役割

# useStateとuseEffectの役割

ボタンを押すとカウントアップしていく簡単な機能を作りながら、useEffectとuseStateの役割について初学者向けに書いて行きたいと思います。

## useStateの役割

まず、普通の変数を使ってカウントを試みます。
```tsx
"use client";
import type React from 'react';
const Home: React.FC = () => {
  let count = 0;

  const setCount = (value: number) => {
    count = value;
    console.log("count up :", count)
  };
  return (
    <div className="home">
      <h1>useEffect and useState demo</h1>
      <p>クリックで数字が増えます</p>
      <button type='button' onClick={() =>{ setCount(count + 1)}}>カウントアップ</button>
      <p>現在のカウント: {count}</p>
    </div>
  );
}
export default Home;  
```
実行してみると画面上のカウントは増えません。コンソールを見てみるとコンソール上では正しくカウントされています。
なぜでしょうか？
これは、レンダリングが起動時の一回しか行われていないことによります。
ボタンを押すとcountは増えますが、レンダリングされないため、画面上では切り替わらないのです。

そこで活躍するのが**useState**です。
useStateでは次のように変数を置きます。
```tsx
const [variable, setVariable] = useState(0) 
(const [変数名, 更新関数名] = useState(初期値))
```
`variable`が変数のように振る舞い、`setVariable(代入する値)`で代入できます。
※このときvariableは定数として定義しており、直接`variable = 1`などのように書き換えてはいけません。

なぜuseStateを使うのか。それはuseStateを使うと、**変数が変化したとき再レンダリングされるから**です。つまり、`setVariable`で`variable`を書き換えると、`variable`を含む部分が再びレンダリングされ、表示上の値が変わるのです。
具体的なコードは以下です。
```tsx
"use client";
import type React from 'react';
import { useState } from 'react';
const Home: React.FC = () => {
  const [count, setCount] = useState(0);

  return (
    <div className="home">
      <h1>useEffect and useState demo</h1>
      <p>クリックで数字が増えます</p>
      <button type='button' onClick={() => setCount(count + 1)}>カウントアップ</button>
      <p>現在のカウント: {count}</p>
    </div>
  );
}
export default Home;  
```
このようにすると、`setCount`で`count`の値が変わると、そのたびに`<p>現在のカウント: {count}</p>`がレンダリングされるので、値の変更が画面に反映されます。

## useEffectの役割
次に、`count`の２倍の数`doubleCount`も画面に表示してみようと思います。
同じようにuseStateを使って書いていきましょう。
```tsx
"use client";
import type React from 'react';
import { useState } from 'react';
const Home: React.FC = () => {
  const [count, setCount] = useState(0);
  const [countDouble, setCountDouble] = useState(count * 2);
  return (
    <div className="home">
      <h1>useEffect and useState demo</h1>
      <p>クリックで数字が増えます</p>
      <button type='button' onClick={() => setCount(count + 1)}>カウントアップ</button>
      <p>現在のカウント: {count}</p>
      <p>カウントの２倍: {countDouble}</p>
    </div>
  );
}
export default Home;  
```
このコードを動かしても、`doubleCount`は変化しません。
なぜなら`setDoubleCount`を呼び出していないからです。
これを直すには`count`の値が書き換わったときにあわせて`setDoubleCount`を呼びたいですね。これを実践できるのが**useEffect**です。
useEffectは次のように書きます。
```tsx
useEffect(() => {
  実行する内容
}, [監視する変数])
```
( 監視する変数は複数指定できて、空にすると初回レンダリング時に一度実行されます。)
このようにすることで、監視する変数が変わったときにコードを実行できます。
これを使って`doubleCount`を表示してみましょう。
```tsx
"use client";
import type React from 'react';
import { useState, useEffect } from 'react';
const Home: React.FC = () => {
  const [count, setCount] = useState(0);
  const [countDouble, setCountDouble] = useState(0);

  useEffect(() => {
    setCountDouble(count * 2);
  }, [count]);

  return (
    <div className="home">
      <h1>useEffect and useState demo</h1>
      <p>クリックで数字が増えます</p>
      <button type='button' onClick={() => setCount(count + 1)}>カウントアップ</button>
      <p>現在のカウント: {count}</p>
      <p>カウントの２倍: {countDouble}</p>
    </div>
  );
}
export default Home;  
```
useEffectで`count`を監視しているので、`count`が増えると`doubleCount`も自動的に増えて行きます。

これはこのようにコンポーネントの引数に設定しても動作します。
```tsx: page.tsx
"use client";
import type React from 'react';
import { useState, useEffect } from 'react';
import Counter from './counter';
const Home: React.FC = () => {
  const [count, setCount] = useState(0);
  const [countDouble, setCountDouble] = useState(0);

  useEffect(() => {
    setCountDouble(count * 2);
  }, [count]);

  return (
    <div className="home">
      <h1>useEffect and useState demo</h1>
      <p>クリックで数字が増えます</p>
      <button type='button' onClick={() => setCount(count + 1)}>カウントアップ</button>
      <Counter count={count} countDouble={countDouble} />
    </div>
  );
}
export default Home;  
```
```tsx:counter.tsx
type CounterProps = {
    count: number;
    countDouble: number;
};
const Counter: React.FC<CounterProps> = ({count, countDouble}) => {
    return (
        <div className="counter">
        <h1>Counter Component</h1>
        <p>現在のカウント: {count}</p>
        <p>カウントの２倍: {countDouble}</p>
        </div>
    );
    }
export default Counter;
```
:::note info
### 「派生した値」はstateにしなくてもOK
今回の例では、あえて useEffect で countDouble を更新していますが、実際には count から計算可能な「派生した値」は、state で管理する必要はありません。今回の例では
```tsx
const [countDouble, setCountDouble] = useState(0);
```
としているところを
```tsx
const countDouble = count * 2;
```
とすれば自動で更新されます。
useEffectは「値が変わったときに関数が実行できる」ものだと理解できれば良いと思います。
詳しく知りたい方はこちらを御覧ください。
https://ja.react.dev/reference/react/useEffect#caveats
:::

## まとめ
 - **useState** 変数の値が変わったときに再レンダリングさせるために使う
 - **useEffect** 変数が変わったときにコードを実行するときに使う