tanish-kr's learning log

Learning output log

JavaScript React

フォーム

フォーム要素はReactにおいて他のDOM要素と少し異なる動作をします

制御されたコンポーネント

HTMLではフォーム要素は通常、自身で状態を保持しており、ユーザの入力に基づいてそれを更新します。 Reactでは、変更されうる状態は通常コンポーネントのstateプロパティに保持され、setState()関数でのみ更新されます。

Reactのstateを信頼できる唯一の情報源とすることで、上述の2つの状態を結合させることが出来ます。そうすることで、フォームをレンダーしているReactコンポーネントが、後続するユーザー入力で起きることも制御出来るようになります。 このような方法でReactによって値が制御される入力フォーム要素は「制御されたコンポーネント」と呼ばれます。

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:
          {/* valueはReactのstateをonChange時に更新した状態のものを利用する */}
          <input type="text" value={this.state.value} onChange={this.handleChange} />
        </label>
      </form>
    );
  }
}

textareaタグ

Reactでは<textarea>はvalue属性を使用する

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('A essay was submitted: ' + this.state.value);
    event.preventDefault();
  }

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

}

selectタグ

Reactではselected属性の代わりに、value属性を親のselectタグで使用します

class FlavorForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: "cocount"};
    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 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>
    );
  }

}

file input タグ

値はユーザだけが設定可能で、プログラムでは操作できないため、Reactでは非制御コンポーネントになる。

ファイルをやり取りする場合、File APIを使用する

class FileInput extends React.Component {
  constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.fileInput = React.createRef();
  }

  handleSubmit(event) {
    event.preventDefault();
    alert(
      `Selected file - ${
        this.fileInput.current.files[0].name
      }`
    );
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Upload file:
          <input type="file" ref={this.fileInput} />
        </label>
        <button type="submit">Submit</button>
      </form>
    );
  }
}

ReactDOM.render(
  <FileInput />,
  document.getElementById("root")
);

複数の入力の処理

複数の制御された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
    });
  }

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