[React][L2] テキストボックスの内容を保持する

# 実施条件
[[React][L1] Stateを用いてコンテンツ(li)を出力する](https://qiita.com/Jochun/items/f1a34240bffd6719a693)を理解していること

# 環境
MacBook Pro (2.3 GHz 8コアIntel Core i9)
macOS 14.0（23A344）
Homebrew 4.3.8
gh 2.52.0

# ソースコードの前に
## フォルダ構成
~~~:folda_structure
├── package.json
├── public/
│   └── index.html
├── src/
│   ├── index.jsx
│   ├── Todo.jsx
│   └── styles.css
│　　
~~~

## index.html
~~~diff_html:index.html
<!DOCTYPE html>
<html lang="en">
  <head> </head>

  <body>
    <div id="root"></div>
  </body>
</html>
~~~

## index.jsx
~~~diff_jsx:index.jsx
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";

import { Todo } from "./Todo";

const rootElement = document.getElementById("root");
const root = createRoot(rootElement);

root.render(
  <StrictMode>
    <Todo />
  </StrictMode>
);
~~~

# ソースコード
## Todo.jsx(旧)
~~~diff_jsx:Todo.jsx
import { useState } from "react";
import "./styles.css";

export const Todo = () => {
  const [incompleteTodos, setIncompleteTodos] = useState([
    "TODOです1",
    "TODOです2",
  ]);
  const [completeTodos, setCompleteTodos] = useState([
    "TODOでした1",
    "TODOでした2",
  ]);

  return (
    <>
      <div className="input-area">
        <input placeholder="TODOを入力"></input>
        <button>追加</button>
      </div>
      <div className="incomplete-area">
        <p className="title">未完了のTODO</p>
        <ul>
          {incompleteTodos.map((todo) => {
            return (
              <li key={todo}>
                <div className="list-row">
                  <p>{todo}</p>
                  <button>完了</button>
                  <button>削除</button>
                </div>
              </li>
            );
          })}
        </ul>
      </div>
      <div className="complete-area">
        <p className="title">完了のTODO</p>
        <ul>
          {completeTodos.map((todo) => {
            return (
              <li>
                <div className="list-row">
                  <p>{todo}</p>
                  <button>戻す</button>
                </div>
              </li>
            );
          })}
        </ul>
      </div>
    </>
  );
};
~~~

## Todo.jsx
~~~diff_jsx:Todo.jsx
import { useState } from "react";
import "./styles.css";

export const Todo = () => {

+ const [todoText, setTodoText] = useState("");
  const [incompleteTodos, setIncompleteTodos] = useState([
    "TODOです1",
    "TODOです2",
  ]);
  const [completeTodos, setCompleteTodos] = useState([
    "TODOでした1",
    "TODOでした2",
  ]);

+ const onChangeTodoText = (event) => setTodoText(event.target.value);

  return (
    <>
      <div className="input-area">
-       <input placeholder="TODOを入力"></input>
+       <input placeholder="TODOを入力" value={todoText} onChange={onChangeTodoText}></input>
        <button>追加</button>
      </div>
      <div className="incomplete-area">
        <p className="title">未完了のTODO</p>
        <ul>
          {incompleteTodos.map((todo) => {
            return (
              <li key={todo}>
                <div className="list-row">
                  <p>{todo}</p>
                  <button>完了</button>
                  <button>削除</button>
                </div>
              </li>
            );
          })}
        </ul>
      </div>
      <div className="complete-area">
        <p className="title">完了のTODO</p>
        <ul>
          {completeTodos.map((todo) => {
            return (
              <li>
                <div className="list-row">
                  <p>{todo}</p>
                  <button>戻す</button>
                </div>
              </li>
            );
          })}
        </ul>
      </div>
    </>
  );
};
~~~

# 解説
## 目的
- `input`タグ(テキストボックス)に入力された内容を、`todoText`に入力（保持）する

## コーディング
1. `input`タグ(テキストボックス)に入力された内容を保持する`State`(`todoText`)を用意する
    - 初期値は`""`
    ~~~diff_jsx:Todo.jsx
    export const Todo = () => {
    
    + const [todoText, setTodoText] = useState("");
      const [incompleteTodos, setIncompleteTodos] = useState([
        "TODOです1",
        "TODOです2",
      ]);
      const [completeTodos, setCompleteTodos] = useState([
        "TODOでした1",
        "TODOでした2",
      ]);
    ~~~

1. `input`タグ(テキストボックス)に入力された`value`を`todoText`に渡す
    - <INS>`input`タグに`onChange`イベントが設定されていないので、`todoText`の初期値は`""`のまま更新できない</INS>
    ~~~diff_jsx:Todo.jsx
      return (
        <>
          <div className="input-area">
    -       <input placeholder="TODOを入力"></input>
    +       <input placeholder="TODOを入力" value={todoText}></input>
            <button>追加</button>
          </div>
    ~~~
1. `input`タグに入力された`value`の変更を検知できるように、`onChange`イベントを設定する
    ~~~diff_jsx:Todo.jsx
      return (
        <>
          <div className="input-area">
    -       <input placeholder="TODOを入力"></input>
    +       <input placeholder="TODOを入力" value={todoText} onChange={}></input>
            <button>追加</button>
          </div>
    ~~~

1. `onChange`イベントが発火した時に、`todoText`を更新する関数(`setTodoText`)が動作するように`onChangeTodoText`を実装する
    
    1. <INS>`input`タグに入力された`value`が変更される度に、`onChangeTodoText`が呼び出される</INS>
    1. <INS>`setTodoText`に`event.target.value`（入力された値）が渡る</INS>
        - `event.target.value`については、[Tips](##Tips)参照
    1. <INS>`todoText`が更新される</INS>
    ~~~diff_jsx:Todo.jsx
    + const onChangeTodoText = (event) => setTodoText(event.target.value);
    
      return (
        <>
          <div className="input-area">
    -       <input placeholder="TODOを入力"></input>
    +       <input placeholder="TODOを入力" value={todoText} onChange={onChangeTodoText}>
    ~~~


## 処理
1. ユーザーがテキストボックスに文字をタイプする
1. イベント`onChange`が発火する
1. 関数`onChangeTodoText`が起動する
1. 更新関数`setTodoText`の引数に`event.target.value`が渡る
1. `State` `todoText`に`event.target.value`が渡る
1. `todoText`が更新される
    - `input`タグ(テキストボックス)に入力された`value`が`State`(`todoText`)に保持される
1. Reactの再レンダリングがトリガーされる
1. `input`タグ(テキストボックス)に入力された`value`が`todoText`（更新された状態）に更新される


## Tips
`event.target.value`
>フォーム要素（例: `<input>`や`<textarea>`）の値を取得するためによく使用されるプロパティです。`event`はイベントオブジェクトであり、`target`はイベントが発生した要素を指します。その中の`value`プロパティが、フォーム要素に入力された現在の値を表します。

ここでは、`event.target.value`を使用する関数`onChangeTodoText`がセットされた`<input>`でイベントが発生した場合、`<input>`内の`value`を取得する。

# イメージ
## Todo.jsx(旧)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/93c98a17-3b56-c639-bacf-7f0e27350415.png)

## Todo.jsx
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/f5f47b5a-8b71-6ebe-b14f-274f6101c266.png)

# 参考リンク
- [React頻出のe.target.valueを理解する](https://note.com/bluecode_inc/n/nad4b2bf498a9)
- [【React】inputに入力された値（value）を取得する](https://ralacode.com/blog/post/get-value-of-input-using-react/)
- [モダンJavaScriptの基礎から始める挫折しないためのReact入門
](https://www.udemy.com/course/modern_javascipt_react_beginner)