10. Forms - accgetter/React GitHub Wiki

formタグ要素は必然的に幾つかの内部ステートを保持するので、
Reactではformタグ要素は少し他のDOM要素とは異なった動きをします。
例えば、次のプレーンHTMLのformは単一のnameという項目を受けていれます:

<form>
  <label>
    Name:
    <input type="text" name="name" />
  </label>
  <input type="submit" value="Submit" />
</form>

このフォームはユーザがサブミットした時に新しいページを開くというデフォルトのHTMLのformの挙動となります。
この挙動はReactでもしっかり対応しています。しかし大半は、
Javascriptのformのsubmissionを制御するファンクションが便利で、
ユーザがformに入力したデータ参照が可能です。
これを達成するスタンダードな方法は、"controlled components"とよばれる技術です。

Controlled Components

HTMLで、例えば<input>, <textarea>, や <select>のようなform要素は典型的にステートを維持し、
ユーザの入力によって更新される。
Reactでは、柔軟なステートは典型的にコンポーネントのプロパティの状態の中で保たれ、
setState() 関数によってのみ更新されます。

Reactのステートを"single source of truth(真の単一ソース)"にする事で2つをつなげる事ができます。
そしてReactのコンポーネントはformを描画し、
その後のユーザの入力で何が起こっても、コントールします。
このようにReactによって入力された値が制御されるinput要素は、"controlled component" と呼ばれます。

例えば、前の例でサブミットされた際に名前の記録をする場合、
controlled componentとしてformを書く事ができます:

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: ''};

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('A name was submitted: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input type="text" value={this.state.value} onChange={this.handleChange} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

CodePenで試す

value はform要素の上でセットされました、表示された値は常に this.state.valueです。
React stateの真のソース化です。
キー入力の度にReact stateの更新のためにhandleChangeが起動します。

"controlled component" では、ステートの変化はhandlerファンクションにひもづけられています。
それの方法は、入力項目の修正またはバリデートの為には、わかりやすい方法です。
例えば、 nameを大文字で入力させたい場合、handleChangeで次のように書きます:

handleChange(event) {
  this.setState({value: event.target.value.toUpperCase()});
}

The textarea Tag

HTMLでは<textarea>要素はその子要素によって定義されます:

<textarea>
  Hello there, this is some text in a text area
</textarea>

Reactでは<textarea>要素はvalue属性を使うやり方です。
このやり方では、formでの<textarea>は通常のformがinputを一行で書くのと同様です。

class EssayForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: 'Please write an essay about your favorite DOM element.'
    };

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('An essay was submitted: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <textarea value={this.state.value} onChange={this.handleChange} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

テキストエリアに何らかのテキストを表示するため、
this.state.valueはコンストラクタで初期化されている事に気づきます。

The select Tag

HTMLでは、<select>要素はドロップダウンリストを作ります。
例えば、このHTMLは味付けのドロップダウンリストを作成します:

<select>
  <option value="grapefruit">Grapefruit</option>
  <option value="lime">Lime</option>
  <option selected value="coconut">Coconut</option>
  <option value="mango">Mango</option>
</select>

selected属性によって初期ではココナッツが選択状態になっていることに注目してください。
Reactでは、selected属性の代わりに、value属性rootのselecttagで使用します。
それは、一箇所だけで更新が必要となるので、controlled componentではより便利です。
例:

class FlavorForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: 'coconut'};

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('Your favorite flavor is: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Pick your favorite La Croix flavor:
          <select value={this.state.value} onChange={this.handleChange}>
            <option value="grapefruit">Grapefruit</option>
            <option value="lime">Lime</option>
            <option value="coconut">Coconut</option>
            <option value="mango">Mango</option>
          </select>
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

CodePenで試す

全般的に、<input type="text">, <textarea>, と <select> はすべて同様です。
これらはcontrolled componentを利用するためにvalue属性を使用します。

Handling Multiple Inputs

複数のinput要素を扱う時、name属性を使いましょう。
それぞれの要素でハンドラーに何をさせるか、event.target.nameの値に基づいて行います。 例:

class Reservation extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isGoing: true,
      numberOfGuests: 2
    };

    this.handleInputChange = this.handleInputChange.bind(this);
  }

  handleInputChange(event) {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;

    this.setState({
      [name]: value
    });
  }

  render() {
    return (
      <form>
        <label>
          Is going:
          <input
            name="isGoing"
            type="checkbox"
            checked={this.state.isGoing}
            onChange={this.handleInputChange} />
        </label>
        <br />
        <label>
          Number of guests:
          <input
            name="numberOfGuests"
            type="number"
            value={this.state.numberOfGuests}
            onChange={this.handleInputChange} />
        </label>
      </form>
    );
  }
}

CodePenで試す

inputのnameに相当するstate keyの更新のために、
どうやってES6のcomputed property nameシンタックスを使うか覚えておきましょう:

this.setState({
  [name]: value
});

これはES5で書いた場合:

var partialState = {};
partialState[name] = value;
this.setState(partialState);

また、setState()は自動で部分的なステートを現在のステートにマージし、 変更があった場合だけ呼ぶ必要があります。

Alternatives to Controlled Components

controlled componetsは時に面倒です。
dataを変更するためいつもイベントハンドラーを書く必要があり、Reactコンポーネントを通して、
すべてのinputのステートにつなげる必要がある。
これは既存コードをReactにコンバートするときに、とくに悩みの種になります。
または、Reactのアプリと、Reactでないライブラリを統合する時とかも。
これらのケースでは、uncontrolled componentsをよく調べて、
別の技術を模索したほうがいいかもしれない。

⚠️ **GitHub.com Fallback** ⚠️