0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Reactを使った開発において「イベント処理」と「フォームデータの管理」は欠かせないテーマです。本記事では、React特有のイベント処理の仕組み、フォームデータの収集方法(受控コンポーネントと非受控コンポーネント)、さらに高階関数やカリー化を活用した実装方法を解説します。

1. Reactのイベント処理の仕組み

Reactイベントの特徴

  • 合成イベント (Synthetic Event)
    Reactではブラウザごとに異なるイベント実装を統一するため、独自の「合成イベント」を提供しています。これにより、クロスブラウザで同じ書き方が可能になります。

  • イベント委譲 (Event Delegation)
    各DOM要素に直接リスナーをつけるのではなく、Reactはイベントをコンポーネントの最上位要素に委譲します。これにより、イベント処理が効率化されます。

  • イベントハンドラの書き方
    JSXではイベント名は キャメルケース で指定する必要があります(例:onClick, onChange)。

使用例

class Demo extends React.Component {
  myRef = React.createRef()
  myRef2 = React.createRef()

  showData = (event) => {
    alert(this.myRef.current.value)
  }

  showData2 = (event) => {
    alert(event.target.value)
  }

  render() {
    return (
      <div>
        <input ref={this.myRef} type="text" placeholder="クリック後表示" />
        <button onClick={this.showData}>左側データを表示</button>
        <input onBlur={this.showData2} type="text" placeholder="フォーカス外れ時に表示" />
      </div>
    )
  }
}

ReactDOM.render(<Demo />, document.getElementById('test'))

ポイントは event.target を使ってイベントが発生した要素を直接取得できる点です。これにより不要なrefの乱用を避けられます(基礎第2弾でお話しした通りrefは必要な時だけ使うべきです)。

2. フォームデータの収集方法

Reactではフォームデータを扱う際に 受控コンポーネント非受控コンポーネント の2種類の方法があります。

2.1 受控コンポーネント(Controlled Component)

フォームの入力値をすべてReactのstateで管理します。入力が変わるたびにstateを更新し、Reactが「唯一のデータソース」となります。

class Login extends React.Component {
  state = { username: '', password: '' }

  saveUsername = (event) => {
    this.setState({ username: event.target.value })
  }

  savePassword = (event) => {
    this.setState({ password: event.target.value })
  }

  handleSubmit = (event) => {
    event.preventDefault()
    const { username, password } = this.state
    alert(`ユーザー名: ${username}, パスワード: ${password}`)
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        ユーザー名:<input onChange={this.saveUsername} type="text" />
        パスワード:<input onChange={this.savePassword} type="password" />
        <button>ログイン</button>
      </form>
    )
  }
}

メリット:
(1) データの流れが一元化され、UIと状態が常に同期する
(2) バリデーションや入力制御が容易

2.2 非受控コンポーネント(Uncontrolled Component)

refを使ってDOM要素に直接アクセスし、入力値を取得します。フォームのデータをReactが直接管理しないため「非受控」と呼ばれます。

class Login extends React.Component {
  handleSubmit = (event) => {
    event.preventDefault()
    const { username, password } = this
    alert(`ユーザー名: ${username.value}, パスワード: ${password.value}`)
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        ユーザー名:<input ref={c => this.username = c} type="text" />
        パスワード:<input ref={c => this.password = c} type="password" />
        <button>ログイン</button>
      </form>
    )
  }
}

メリット:

(1) 実装がシンプル
(2) 小規模なフォームに向く

デメリット:

(1) Reactの状態管理から外れるため、大規模フォームでは扱いにくい

高階関数とカリー化を使ったフォーム処理

まず高階関数とは?

・他の関数を引数に取る関数
・関数を返す関数
このどちらかを満たす関数を「高階関数」と呼びます。
例:mapsetTimeoutPromiseなど

カリー化

定義:1つの関数で複数の引数を処理する代わりに、関数を返す関数として引数を分けて処理する手法です。カリー化は高階関数の一つの具体的な応用例です。

function sum(a) {
  return (b) => {
    return (c) => {
      return a + b + c
    }
  }
}

Reactでの応用:
クラスコンポーネントのイベント処理において、処理関数に引数を渡す場合、必ずカリー化を使う必要があります。
まずコードを見せます:

class Login extends React.Component {
  state = { username: '', password: '' }

  saveFormData = (dataType) => {
    return (event) => {
      this.setState({ [dataType]: event.target.value })
    }
  }

  handleSubmit = (event) => {
    event.preventDefault()
    const { username, password } = this.state
    alert(`ユーザー名: ${username}, パスワード: ${password}`)
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        ユーザー名:<input onChange={this.saveFormData('username')} type="text" />
        パスワード:<input onChange={this.saveFormData('password')} type="password" />
        <button>ログイン</button>
      </form>
    )
  }
}

ここでonChange={this.saveFormData('username')}とonChange={this.saveFormData('password')}の二箇所で引数を渡しましたので、実際にsaveformDataの返り値に相当します。このことでsavaDataFormの返り値は必ず関数でなかればならず、しかも外部の関数(saveFormData)と内部の関数(返り値)はそれぞれdataTypeとeventをパラメータとして持ちます。
つまりここでカリー化を使う必要があります。
もちろんこの場合でカリー化を使わず、二つの関数に分けて(例えばsaveFormUsernameとsaveFormPassword)引数を渡さない形に書いても実装できますが、フォームの入力をより効率的にまとめるという点からは、やはりカリー化の書き方のほうが優れます。このようにすれば、複数の入力欄を1つの関数で管理できます。

まとめ

・イベント処理

Reactは合成イベントとイベント委譲を採用しており、効率的かつクロスブラウザ対応が可能です。

・ フォームデータの収集

受控コンポーネント → stateでデータを完全に管理
非受控コンポーネント → refでDOMに直接アクセス

・高階関数とカリー化

フォーム処理をシンプルかつ再利用可能にする強力なテクニックです。

Reactを使ったフォーム開発では、まず受控コンポーネントをベースに設計し、必要に応じて非受控コンポーネントや高階関数を活用するのがベストプラクティスです。

0
1
0

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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?