LoginSignup
35
26

More than 5 years have passed since last update.

ReactでできるだけシンプルにForm実装

Last updated at Posted at 2018-03-17

Reactのフォーム実装で消耗したのでライブラリ等使わずにできるだけシンプルにフォーム実装する方法考えてみた。

方針

  • 項目ごとのリアルタイムなバリデーションやエラー表示はしっかりやる
  • stateに入力値を入れない
  • できるだけform本来の機能を使う
  • IE11以上に対応
  • FormDataは使わない(IEがentries()やkeys()に対応していないため)

前提環境

  • Babel
  • ES2017
  • object-rest-spreadを使用

サンプル

実際に動かせるサンプルはJSFiddleに作ってるのでこちらからどぞ。
https://jsfiddle.net/3ywe2tmk/33/

コード

const FIELDS = {
  userId: 'userId',
  age: 'age',
};

class Form extends React.Component {
  constructor() {
    super();

    this.state = {
      errors: {},
      isSubmitEnabled: false,
    };

    this.elements = null;

    this.handleFormChange = this.handleFormChange.bind(this);
    this.handleFormBlur = this.handleFormBlur.bind(this);
    this.handleFormSubmit = this.handleFormSubmit.bind(this);
  }

  validate(field, value) {
    if (!value) {
      return true;
    }

    let isValid = true;
    switch (field) {
      case FIELDS.userId:
        isValid = /^[0-9a-zA-Z]+$/.test(value);
        break;
      case FIELDS.age:
        isValid = /^[0-9]+$/.test(value);
        break;
      default:
        break;
    }

    return isValid;
  }

  setSubmitEnabled() {
    if (!this.elements) {
      return;
    }

    const isNoEmptyFields = Object.values(FIELDS).every(field => this.elements[field].value);
    const isNoErrors = Object.values(this.state.errors).every(error => !error);

    this.setState({
      isSubmitEnabled: isNoEmptyFields && isNoErrors,
    });
  }

  handleFormChange() {
    this.setSubmitEnabled();
  }

  handleFormBlur(event) {
    const field = event.target.name;

    // validation
    this.setState({
      errors: {
        ...this.state.errors,
        [field]: !this.validate(field, event.target.value),
      },
    }, () => {
      this.setSubmitEnabled();
    });
  }

  handleFormSubmit(event) {
    event.preventDefault();


    // form値取得
    const params = {
      userId: this.elements[FIELDS.userId].value,
      age: this.elements[FIELDS.age].value,
    };

    alert(JSON.stringify(params, null, '  '));
  }

  render() {
    const { errors } = this.state;
    return (
      <form
        onChange={this.handleFormChange}
        onBlur={this.handleFormBlur}
        onSubmit={this.handleFormSubmit}
        ref={el => this.elements = el && el.elements}
      >
        <div>
          <span className="label">ユーザーID</span>
          <input
            type="text"
            name={FIELDS.userId}
            />
        </div>
        {
          this.state.errors[FIELDS.userId] &&
            <p className="error">
              半角英数字で入力してください。
            </p>
        }
        <div>
          <span className="label">年齢</span>
          <input
            type="text"
            name={FIELDS.age}
            />
        </div>
        {
          this.state.errors[FIELDS.age] &&
            <p className="error">
              半角数字で入力してください。
            </p>
        }
        <button
          type="submit"
          disabled={!this.state.isSubmitEnabled}
          >submit</button>
      </form>
    );
  }
}

ReactDOM.render(
  <Form/>,
  document.getElementById('container')
);

ポイント

form.elements

form.elementsから入力値を参照。
stateに入力値を溜め込まなくてもここからkey指定で入力値を取得できます。
例: form.elements.userId.value
https://developer.mozilla.org/ja/docs/Web/API/HTMLFormElement/elements

onChange

formのonChangeでフォーム全体の入力値変更を検知。

onBlur

formのonBlurでフォーム全体のblurを検知してvalidationを実行。

onSubmit

formのonSubmitでsubmitを検知してform.elementsから入力値を取得。

35
26
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
35
26