📚

onChange地獄からの脱出:Knockout.jsのdata-bindをReactで活用する

2025/03/28に公開

onChange地獄からの脱出:Knockout.jsのdata-bindをReactで活用する

はじめに

Reactを使ってフォームを作るとき、onChange による状態更新が必須です。

<input value={value} onChange={e => setValue(e.target.value)} />

これはReactの「制御されたコンポーネント」という設計によるものですが、地味に面倒です。

実はKnockout.jsのdata-bindとreact-koを使えば、ReactのフォームでもonChangeを書かずに済む方法があります。

本記事では、

  • なぜReactはonChangeが必要なのか?
  • それをKOのバインディングでどう解決できるか?
  • react-ko を使ってどう組み合わせるのか?

という観点から、Reactユーザーの「イベント地獄」を救う実践的アプローチを紹介します。

Reactだけでフォームを作る場合の苦しみ

Reactは入力要素の状態を「コンポーネントの状態(state)」と結びつけるため、フォーム入力には onChange を毎回書く必要があります。

const [name, setName] = useState('')

<input value={name} onChange={e => setName(e.target.value)} />

シンプルなフォームでも、入力項目が多くなると useStateonChange の量が激増します。

KOのdata-bindならonChangeは不要

Knockoutでは、observableを定義して data-bind="value: name" を使えば、
入力要素とデータが自動で同期されます。

<input data-bind="value: name" />

これだけで双方向バインディングが成立します。
Reactから見ると「なんでonChangeなくていいの!?」という不思議な体験ですが、KOはそれを昔からやっていました。

解決策:react-koでKOのバインディングをReactに持ち込む

react-ko を使えば、Reactコンポーネントの中で data-bind を記述できるようになります。

つまり、ReactのJSX内でKOのフォームバインディングが使えるということです。

インストール方法

npm install react-ko knockout

GitHub リポジトリはこちら

使用例:KO observableでReactフォームを構築

import ko from 'knockout'
import { KnockoutScope } from 'react-ko'

export function KoInput({ value }) {
  const vm = { value }

  return (
    <KnockoutScope viewModel={vm}>
      <input data-bind="value: value" />
    </KnockoutScope>
  )
}

// 使用例
const viewModel = {
  name: ko.observable('Alice')
}

<KnockoutScope viewModel={viewModel}>
  <KoInput value={viewModel.name} />
</KnockoutScope>

このように、useStateonChange も不要。
KOのobservableと data-bind に任せることで、
Reactでも直感的に双方向バインディングが実現できます。

おわりに

onChangeを書きたくない。
でもReactで構築されたUIの中で、状態管理の責務は保ちたい。

そんな悩みに対して、Knockout.jsのdata-bindという昔ながらの知恵を活かすことは、ある意味で逆転の発想かもしれません。

react-koを使えば、Reactの世界にKOのバインディングの便利さを取り入れることができます。

ReactはUIの状態を厳密に管理できる反面、フォームのような日常的なUIでも毎回イベント処理を書く必要があります。

KOの data-bind は、そういった煩雑さを取り除く強力な手段です。

react-ko を使えば、そのKOの恩恵をReactの中で活かせます。

「onChange地獄に疲れた…」というReactユーザーは、ぜひ一度 react-ko を試してみてください。

Discussion