1.はじめに
React要素のイベント処理は、DOM要素に似ています。しかし、少し構文の違いがあります:
- Reactイベントバインディングプロパティは、キャメルケース、たとえば小文字の代わりに、ネイティブイベントはすべて小文字のonclickであり、ReactのイベントはハンプしたonClickです。
- JSX構文が必要な場合イベントハンドラーとして関数を渡す、文字列の代わりに(DOM要素の記述方法)。
- Reactイベントはネイティブイベントではなく、合成イベントです。
- Reactのもう1つの違いは、falseを返すことでfalseの動作を防止できないことです。明示的にe.preventDefault()を使用する必要があります。
HTMLは通常、次のように記述されます。
<button onclick="clickHandle()">提交</button>
<script>
function clickHandle(e){
e.preventDefault(); //阻止默认事件
//或者使用如下的写法
return false;
}
</script>
Reactの表現は次のとおりです。
<button onClick={clickHandle}>提交</button>
<script>
function clickHandle(e){
e.preventDefault(); //阻止默认事件,不能使用return false
}
</script>
2. Reactがイベントをバインドするいくつかの方法
- ES6クラス構文を使用してコンポーネントを定義すると、イベントハンドラーがクラスのメソッドになります。
- JSXコールバック関数では、これに注意する必要があります。クラスのメソッドは、デフォルトではこれをバインドしません。this.handleClickをバインドしてonClickに渡すのを忘れた場合、この関数を呼び出したときのthisの値は未定義になります。
- 通常、メソッドの後に()を追加しない場合(例:onClick = {this.handleClick})、これをこのメソッドにバインドする必要があります。
2.1方法1
コールバック関数で矢印関数を使用し、render()にインライン矢印関数を直接記述します(非推奨)。このメソッドの問題は、render()が実行されるたびに異なるコールバック関数が作成されることです。ほとんどの場合、これは問題ありません。ただし、このコールバック関数がプロパティ値として低レベルのコンポーネントに渡される場合、これらのコンポーネントは追加で再レンダリングされる場合があります。
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class Box extends Component {
handleClick(e,val){
console.log(e,val);
}
render() {
return (
<button onClick={(e)=>this.handleClick(e,'aa')}>添加</button>
);
}
}
ReactDOM.render(
<Box />,
document.getElementById('root')
);
2.2方法2
render()メソッドで、bindを使用してこれをバインドします(非推奨)。コンポーネントで非矢印関数を直接定義してから、レンダリングで直接使用します。onClick={this.handleClick.bind(this)}
このメソッドの欠点は、bindを使用してこれをバインドするたびに、コードが冗長になることです。
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class Box extends Component {
handleClick(val,e) { //事件对象e要放在最后
console.log(val,e);
}
render() {
return (
<button onClick={this.handleClick.bind(this, 'aa')}>添加</button>
);
}
}
ReactDOM.render(
<Box />,
document.getElementById('root')
);
2.3方法3
プロパティ初期化子を使用してコールバック関数を正しくバインドし(推奨)、矢印関数を使用してコンポーネントのメソッドを定義します。このメソッドの欠点は、パラメーターをカスタマイズできないことです。
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class Box extends Component {
handleClick =(e)=>{
console.log(e);
}
render() {
return (
<button onClick={this.handleClick}>添加</button>
);
}
}
ReactDOM.render(
<Box />,
document.getElementById('root')
);
2.4方法4
非矢印関数のメソッドをコンポーネントで直接定義し、コンストラクタで(this)をバインドします(推奨)。このメソッドの利点は、パフォーマンスが向上することです。render()が何回実行されても、最終的には同じ参照を指します。この方法の欠点は、パラメーターをカスタマイズできないことです。
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class Box extends Component {
constructor(){
super();
this.myhandleClick = this.handleClick.bind(this);
}
handleClick(e){
console.log(e);
}
render() {
return (
<button onClick={this.myhandleClick}>添加</button>
);
}
}
ReactDOM.render(
<Box />,
document.getElementById('root')
);
3. Reactイベントパラメータ
通常のブラウザと同様に、イベントhandleClickは、通常のブラウザイベントオブジェクトと基本的に同じメソッドとプロパティを含むイベントオブジェクトに自動的に渡されます。REACT違いがあることであるevent
オブジェクトは、ブラウザによって提供されるのではなく、独自の内部に構築します。また有しevent.stopPropagation
、event.preventDefault
このような従来の方法。
イベントハンドラーに追加のパラメーターを渡します。通常は上記の2つのメソッド(2.1、2.2)を使用します。
<button onClick={(e)=>this.handleClick(e, 'aa')}>添加</button>
<button onClick={this.handleClick.bind(this, 'aa')}>添加</button>
bindメソッド、クラスコンポーネントで定義されたリスナー関数を介してリスナー関数にパラメーターを渡すことにより、渡されたパラメーターの後にイベントオブジェクトeを配置する必要があることに注意してください。
3.1サブコンポーネントのパラメーターの変更
親コンポーネントから渡されたパラメータを子コンポーネントで変更します。より推奨される方法は、親コンポーネントでメソッドを定義props
し、子コンポーネントで親コンポーネントのメソッドを呼び出し、子コンポーネントに渡してから、子コンポーネントでthis.props.method
呼び出すことです。以下の例をご覧ください。
サブコンポーネントのコード:
class Button extends Component {
handleClick(){
//执行DOM元素的 change属性
this.props.change();
}
render() {
return (
<button onClick={()=>this.handleClick()}>
{this.props.children}
</button>
);
}
}
親コンポーネントのコード:
class Counter extends Component {
constructor() {
super();
this.state = {
count: 0
}
}
handleChange(type) {
this.setState((preState, props) => {
count: preState.count + 1
}
}, () => { })
}
render() {
return (
<div >
<Button change={() => this.handleChange()}>-</Button>
</div>
);
}
}
4.フォームイベント
HTMLフォーム要素はReactの他のDOM要素とは異なります。これは、フォーム要素が最初から内部状態を保持しているためです。
HTMLでは、<input>、<textarea>、<select>などのフォーム要素は独自の状態を維持し、ユーザー入力に基づいて更新されます。しかし、Reactでは、変数の状態は通常、コンポーネントの状態属性に保存され、setState()メソッドでのみ更新できます。
4.1制御されるコンポーネント
のために制御されたコンポーネントの場合、入力値は常にReactの状態によって駆動されます。フォームをレンダリングするReactコンポーネントも、ユーザー入力中にフォームに何が起こるかを制御します。このようにReactによって制御されるフォーム入力要素は、「制御されるコンポーネント」と呼ばれます。
たとえば、ユーザーが入力したすべての小文字を大文字に変換する場合は、フォームを制御されたコンポーネントとして記述できます。
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class Form extends Component {
constructor() {
super();
this.state = {name: ""}
}
handleChange(event) {
this.setState({
name: event.target.value.toUpperCase() // 将输入的字母转成大写
})
}
render() {
return (
<div>名称:<input type="text" value={this.state.name} onChange={this.handleChange.bind(this)} /></div>
);
}
}
ReactDOM.render(
<Form />,
document.getElementById('root')
);
value属性はform要素に設定されているため、表示される値は常にthis.state.valueになりますこれにより、Reactの状態が唯一のデータソースになります。onChangeイベントを使用して、入力の変更を監視し、状態を変更します。ハンドルチェンジによるReactの状態は、キーが押されるたびに実行および更新されます、文字を大文字に変換します。これにより、表示された値は、ユーザーが入力すると更新されます。
4.2複数の入力要素
- 処理する入力要素が複数ある場合は、各要素に名前属性を追加する基づいてハンドラ聞かせするには
event.target.name
何をすべきかの選択の値。 - Reactでは、<textarea>は代わりにvalue属性を使用します。このように、<textarea>を使用するフォームは、1行入力を使用するフォームに非常に似ています。
- Reactでは、[選択]ドロップダウンメニューはselected属性を使用しませんが、value属性を使用してルート選択タグの選択されたアイテムを示します。Selectが複数選択の場合、対応する状態は配列になります。
- 注:<input type =“ file”>の値は読み取り専用であるため、Reactでは制御されていないコンポーネントです。
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class Form extends Component {
constructor() {
super();
this.state = {
name: "",
desc: "",
city: [1,2]
}
}
handleChange(event) {
if(event.target.name==='city'){
this.state.city.push(event.target.value);
this.setState({})
return;
}
this.setState({
[event.target.name]: event.target.value
})
}
render() {
return (
<div>
名称:<input type="text" value={this.state.name} name="name" onChange={this.handleChange.bind(this)} />
描述:<textarea name="desc" value={this.state.desc} onChange={this.handleChange.bind(this)}></textarea>
城市:<select name="city" multiple
value={this.state.city}
onChange={this.handleChange.bind(this)}>
<option value="1">北京</option>
<option value="2">上海</option>
<option value="3">天津</option>
</select>
</div>
);
}
}
ReactDOM.render(
<Form />,
document.getElementById('root')
);
全体として、これにより、<input type =“ text”>、<textarea>、<select>などのタグが非常によく似ています。これらはすべて、制御されたコンポーネントの実装に使用できるvalue属性を受け入れます。
4.3制御されたコンポーネントの適用シナリオ
制御されたコンポーネントのアプリケーションシナリオ:ユーザー入力を監視し、ユーザーが入力したデータを変更できます。たとえば、上記は入力文字を大文字に変換し、ユーザー入力が空かどうかを判断します。
検証、アクセスフィールドの追跡、フォーム送信の処理を含む完全なソリューションを見つけたい場合は、Formikを使用することをお勧めします。ただし、制御されたコンポーネントと状態の管理にも基づいています
データが変化するすべての方法に対してイベントハンドラーを記述し、すべての入力状態をReactコンポーネントに渡す必要があるため、制御されたコンポーネントの使用は扱いにくい場合があります。このような場合は、制御されていないコンポーネントを使用することができます。これは、入力フォームを実装するもう1つの方法です。
4.4制御されていないコンポーネント
制御されていないコンポーネント、コンポーネントによって表示される値は、状態によって完全に制御されていません。ref属性を使用して、render()によって出力されるコンポーネントにバインドします。Vueでのrefの使用と同様に、ref属性を介してバインドされたDOM要素を取得します。
refの使用方法:
ref属性値が静的コンテンツの場合:
1. ref属性をrenderの戻り値にバインドします;
2. this.refsを介してバインドされたDOM要素を取得します。
ref属性値がstateの場合:
1. importを使用して、react.createRefをインポートします。2。state
をrefの属性値として使用し、renderの戻り値に
バインドします。
import React, { Component,createRef } from 'react';
import ReactDOM from 'react-dom';
class Form extends Component {
constructor() {
super();
this.title = createRef()
}
handleSubmit = () => {
console.log(this.title.current.value)
console.log(this.refs.myInput.value)
}
render() {
return (
<div>
<input type="text" ref={this.title}/>
<input type="text" ref='myInput'/>
<button onClick={this.handleSubmit}>提交</button>
</div>
);
}
}
ReactDOM.render(
<Form />,
document.getElementById('root')
);