ReactのuseStateによるステート管理と再レンダリングの仕組み


## 対象者
この記事は、Reactにおける状態管理とコンポーネントの再レンダリングについて学びたい方を対象としています。基本的なJavaScriptの知識とReactの基礎を理解していることが前提となります。useStateフックの概念と使用方法をより深く理解したい方に特におすすめです。

## 環境
```
OS: macOS Sonoma 14.4
開発環境: Visual Studio Code (VSCode)
Reactバージョン: React v18
```

## 内容
Reactでは、コンポーネントの状態管理と再レンダリングの挙動がJavaScriptの基本的な書き方とは異なる仕組みに基づいています。本記事では、その違いを具体例を交えて解説します。


## 状態の管理

### useStateを使用しない場合

```
const Example = () => {
    let displayVal; // 入力欄の値を格納する変数
    console.log(displayVal);

    return (
        <>
            <input type="text"
                onChange={(e) => {
                    displayVal = e.target.value;
                }} /> = {displayVal}
        </>
    );
};

export default Example;

```

このコードでは、入力された値を変数displayValに格納し、それを画面に表示しようとしています。しかし、Reactではこの方法は期待通りに動作しません。



### useStateを使用

Reactでは、状態の管理にuseStateフックを使用します。useStateの基本的な使い方は以下の通りです。

**分割代入を使用しない書き方**
```
import { useState } from 'react';

const Example = () => {
    let valArry = useState("hello");
    console.log(valArry);

    return (
        <>
            <input type="text"
                onChange={(e) => {
                    const setFn = valArry[1];
                    setFn(e.target.value);
                }} /> = {valArry[0]}
        </>
    );
};

export default Example;
```

**コンソールの結果**

![スクリーンショット 2024-03-26 8.14.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2401767/65db4c71-3fd2-b375-dd8b-f4d49b426582.png)


useStateは、現在の状態の値とその値を更新する関数を配列で返します。しかし、より読みやすく効率的な書き方があります。

### リファクタリング: 本来のuseStateの書き方

```
import { useState } from 'react';

const Example = () => {
    const [val, setVal] = useState("hello");
    console.log(val);

    return (
        <>
            <input
                value={val}
                onChange={(e) => setVal(e.target.value)}
            /> = {val}
        </>
    );
};

export default Example;

```

この書き方により、状態の読み取りと更新が直感的に行えるようになります。

## 初期コードが動かなかった理由を検証

初期のコードでは、コンポーネントの状態が適切に管理されていませんでした。理由としては、再実行(レンダリング)するタイミングはブラウザを再読み込みした時のみだからです。


#### Reactコンポーネントで状態を管理するには、useStateフックを使用して以下のような処理を行う必要があります。

1. Reactコンポーネントの **再実行(レンダリング)** を依頼し、新しいReact要素を作成してもらう
2. 変更した値を **State** に保存し、React内部で保持管理する


### 再レンダリングの仕組み
- useStateを使用しない場合、コンポーネントの状態変更が反映されないため、再レンダリングは発生しない
- useStateを使用する場合、状態が更新されるたびにコンポーネントは再レンダリングされる


`useState`を使用することで、Reactは状態の更新に応じてコンポーネントの再レンダリングを適切に行うことができるようになります。これにより、ユーザーインターフェースは常に最新の状態を反映することが可能となり、動的なアプリケーションの開発が容易になります。

以下の例では、入力欄に入力されるたび、状態の更新とコンポーネントの再レンダリングが行われることを確認できます。


### useStateを使用しないケース

**code**

```
import { useState } from "react";

const Example = () => {

    let displayVal;

    console.log('再レンダリングされました');

    return (
        <>
            <input
                type="text"
                onChange={(e) => {
                    console.log(e.target.value);
                    displayVal = e.target.value;
                }}
            /> = {displayVal}
        </>
    );
};

export default Example;

```

**結果(コンソール)**

![スクリーンショット 2024-03-26 8.24.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2401767/fa1d0698-d567-1841-8a96-2e92ba89bc08.png)



### useStateを使用するケース

**code**
```
import { useState } from "react";

const Example = () => {
  const [val, setVal] = useState("");

  console.log('再レンダリングされました');
  
  return (
    <>
      <input
        type="text"
        value={val}
        onChange={(e) => {
          console.log(e.target.value);
          setVal(e.target.value);
        }}
      /> = {val}
    </>
  );
};

export default Example;

```

**結果(コンソール)**
![スクリーンショット 2024-03-26 8.25.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2401767/ad136425-419d-8372-5042-a44b70ad74a3.png)


このログは、ユーザーが入力欄に値を入力するたびに`useState`を通じて状態が更新され、それに伴いコンポーネントが再レンダリングされる様子を示しています。
このプロセスにより、Reactアプリケーションはユーザーの操作に迅速に反応し、インターフェースを最新の状態に保つことができます。