【React】入力用コンポーネント作成の基本

# 入力コンポーネントを作ろう！

入力するのでコンポーネント内部に入力されたデータを保持しないと。
こんな感じかな？

```tsx
import React from "react";

export const IncorrectTextBox = (props: Props) => {
  const [value, setValue] = React.useState("");

  return (
    <label style={{ display: "block" }}>
      {`${props.label} `} 
      <input
        value={value}
        onChange={event => setValue(event.target.value)} />
    </label>
  );
}
```

使うときはこんな感じだね。

```tsx
const App = () => {
  return (
    <div style={{ maxWidth: 400, margin: "auto", padding:50 }}>
      <IncorrectTextBox label="Input your fisrt name." />
      <IncorrectTextBox label="Input your last name." />
    </div>
  )
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299625/4eb09db2-6d09-4934-27b4-ef0aa02053ad.png)

ちゃんと入力できてるみたい！完璧！

## 入力を確認するエリアを用意したい？

入力確認をするためにフルネームを表示する要素を用意しよう！

```tsx
const App = () => {
  return (
    <div style={{ maxWidth: 400, margin: "auto", padding:50 }}>
      <IncorrectTextBox label="Input your first name." />
      <IncorrectTextBox label="Input your last name." />
      <div>{`${firstName} ${lastName}`}</div>
    </div>
  )
}
```

あとは`firstName`と`lastName`さえ取れれば表示できる！

`IncorrectTextBox`コンポーネントからそれぞれの入力値を取得するにはどうしたらいいだろうか？

どうしたらいいだろうか？

どうしたらいいだろうか…？

<br/>
<br/>
**取れません。**

# 制御されたコンポーネントにしましょう

ユーザーの入力を受け付けるコンポーネントの基本は

- 入力値を`props`で受け付ける
- 変更があったら実行する関数を`props`で受け付ける

の2点です。各々で状態を持つのではなく、そのコンポーネントを利用する側に制御されるように設計します。

例えばフリーのテキスト入力ならば下のようになります。

```tsx
interface RevolutionaryTextBoxProps {
  value: string,
  onChange: (value: string) => void,
}

export const RevolutionaryTextBox = (props: RevolutionaryTextBoxProps) => {
  return (
    <input
      type="text"
      value={props.value}
      onChange={event => props.onChange(event.target.value)} />
  );
}
```
TypeScriptなので`interface`を定義しています。
`props`で`string`型の引数`value`を受け取ります。そして、ユーザーが入力するたびに入力後の新規の値を渡して実行する関数を受け取り、実際にユーザーの入力のたびに実行されるようにしておきます。

そしてこの入力コンポーネントを利用する側が`state`を管理します。

```tsx
const App = () => {
  const [firstName, setFirstName] = React.useState("");
  const [lastName, setLastName] = React.useState("");

  return (
    <div style={{ maxWidth: 750, margin: "20px auto" }}>
      <label>
        FirstName
        <RevolutionaryTextBox
          value={firstName}
          onChange={setFirstName} />
      </label>
      <label>
        LastName
        <RevolutionaryTextBox
          value={lastName}
          onChange={setLastName} />
      </label>
      <div>{`${firstName} ${lastName}`}</div>
    </div>
  )
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299625/871f0667-c8cc-a169-d6ae-0292a597b869.png)
("Revolutionary"な背景色にしました。笑)


`string`型の入力を受け付ける簡単なコンポーネント例を出しましたが、これが`number`型の数値入力でも`boolean`型のトグルスイッチでもスライドバーでもDatePickerでも基本は同じです。
`props`経由で入力対象のデータ型の値と、入力後に新規の値を引数に渡して実行される関数を受け取るようなコンポーネントにします。

こうすることで、例えば他の入力コンポーネントの値によって目的の入力コンポーネントも変更される、というようなフォームも実装することができます。

```tsx
const App = () => {
  const [firstName, setFirstName] = React.useState("");
  const [lastName, setLastName] = React.useState("");

  return (
    <div className="container" style={{ maxWidth: 750, margin: "20px auto" }}>
      <label>
        FirstName
        <RevolutionalyTextBox
          value={firstName}
          onChange={value => {
            setFirstName(value);
            setLastName(value);  // setLastName()も同時に呼び出す
          }} />
      </label>
      <label>
        LastName
        <RevolutionalyTextBox
          value={lastName}
          onChange={setLastName} />
          <div>{`${firstName} ${lastName}`}</div>
      </label>
    </div>
  )
}
```

![タイトルなし.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299625/36ce5292-96e0-9df6-ba84-135b09a92334.gif)

# 終わり

わたくしなんと9ヶ月の無職期間を終えて4月よりWeb企業に就職しました🎊
念願だったReactとTypeScriptを業務で扱えることになりました🎉

同様に新しくReactを始めた方がいらっしゃると思います。
そんな方に読んでいただければ幸いです。