フォーム
Preact のフォームは、HTML とほぼ同じように動作します。コントロールをレンダリングし、イベントリスナーをアタッチします。
主な違いは、ほとんどの場合、value
が DOM ノードではなく Preact によって制御されることです。
制御コンポーネントと非制御コンポーネント
フォームコントロールについて話すとき、「制御コンポーネント」と「非制御コンポーネント」という言葉がよく出てきます。この説明は、データフローの処理方法を参照しています。DOM は双方向データフローを持ちます。これは、すべてのフォームコントロールがユーザー入力を自分で管理するためです。単純なテキスト入力は、ユーザーが入力するたびに常にその値を更新します。
一方、Preact のようなフレームワークは一般的に一方向データフローを持ちます。コンポーネントはそこで値自体を管理しませんが、コンポーネントツリーの上位にある別のものが管理します。
// Uncontrolled, because Preact doesn't set the value
<input onInput={myEventHandler} />;
// Controlled, because Preact manages the input's value now
<input value={someValue} onInput={myEventHandler} />;
一般的に、常に制御コンポーネントを使用することをお勧めします。ただし、スタンドアロンコンポーネントを作成する場合やサードパーティの UI ライブラリをラップする場合は、コンポーネントを非 Preact 機能のマウントポイントとして単純に使用することも役立つ場合があります。このような場合、「非制御」コンポーネントはタスクに適しています。
ここで注意すべき点は、値を
undefined
またはnull
に設定すると、本質的に非制御になることです。
シンプルなフォームの作成
ToDoアイテムを送信するシンプルなフォームを作成してみましょう。そのためには、<form>
要素を作成し、フォームが送信されるたびに呼び出されるイベントハンドラーをバインドします。テキスト入力フィールドについても同様のことを行いますが、値をクラス自体に保存することに注意してください。お分かりのように、ここでは制御入力を使用しています。この例では、入力値を別の要素に表示する必要があるため、非常に便利です。
class TodoForm extends Component {
state = { value: '' };
onSubmit = e => {
alert("Submitted a todo");
e.preventDefault();
}
onInput = e => {
this.setState({ value: e.currentTarget.value })
}
render(_, { value }) {
return (
<form onSubmit={this.onSubmit}>
<input type="text" value={value} onInput={this.onInput} />
<p>You typed this value: {value}</p>
<button type="submit">Submit</button>
</form>
);
}
}
REPL で実行セレクト入力
<select>
要素は少し複雑ですが、他のすべてのフォームコントロールと同様に動作します。
class MySelect extends Component {
state = { value: '' };
onChange = e => {
this.setState({ value: e.currentTarget.value });
}
onSubmit = e => {
alert("Submitted " + this.state.value);
e.preventDefault();
}
render(_, { value }) {
return (
<form onSubmit={this.onSubmit}>
<select value={value} onChange={this.onChange}>
<option value="A">A</option>
<option value="B">B</option>
<option value="C">C</option>
</select>
<button type="submit">Submit</button>
</form>
);
}
}
REPL で実行チェックボックスとラジオボタン
チェックボックスとラジオボタン(<input type="checkbox|radio">
)は、制御されたフォームを作成するときに最初は混乱を招く可能性があります。これは、非制御環境では、通常、ブラウザがチェックボックスまたはラジオボタンの「切り替え」または「チェック」を許可し、「変更」イベントをリスンして新しい値に反応するためです。ただし、この手法は、状態とプロパティの変更に応じて UI が常に自動的に更新されるという世界観にはうまく適合しません。
手順:チェックボックスで「変更」イベントをリスンするとします。これは、ユーザーがチェックボックスをチェックまたはチェックを外したときに発生します。変更イベントハンドラーで、チェックボックスから受信した新しい値を
state
に設定します。これにより、コンポーネントの再レンダリングがトリガーされ、チェックボックスの値が state の値に再割り当てされます。これは不要です。なぜなら、DOM から値を要求したばかりで、次に望む値で再レンダリングするように指示したからです。
そのため、「入力」イベントをリスンする代わりに、「クリック」イベントをリスンする必要があります。これは、ユーザーがチェックボックスまたは関連付けられた<label>
をクリックしたときにいつでも発生します。チェックボックスはブール値true
とfalse
の間で切り替わるだけなので、チェックボックスまたはラベルをクリックすると、state にある値を反転するだけで、再レンダリングがトリガーされ、チェックボックスに表示される値が目的の値に設定されます。
チェックボックスの例
class MyForm extends Component {
toggle = e => {
let checked = !this.state.checked;
this.setState({ checked });
};
render(_, { checked }) {
return (
<label>
<input
type="checkbox"
checked={checked}
onClick={this.toggle}
/>
check this box
</label>
);
}
}
REPL で実行