Event handlers
React นั้นได้มีการเตรียม attributes ต่าง ๆ ที่ใช้สำหรับการจัดการกับ event ไว้เรียบร้อยแล้ว ซึ่งวิธีใช้ทั่วไปนั้นแทบจะเหมือนกับวิธีการจัดการ event ใน DOM ที่เราคุ้นเคยเลย โดยจะมีความแตกต่างกันเพียงเล็กน้อย เช่น การใช้ camelCase เป็นชื่อ attribute หรือการส่ง function แทนที่จะเป็น string เป็นต้น
1
const theLogoIsClicked = () => alert('Clicked');
2
3
// onClick event
4
<Logo onClick={ theLogoIsClicked } />
5
6
// onChange event
7
<input
8
type='text'
9
onChange={event => theInputIsChanged(event.target.value) } />
Copied!
ส่วนใหญ่แล้วเรามักจะจัดการ event กันภายในคอมโพเนนท์ที่สร้าง event นั้นขึ้นมา เช่นในตัวอย่างข้างล่าง เรามี button อยู่ในคอมโพเนนท์ Switcher แล้วเราต้องการให้การคลิกที่ button ไปรันคำสั่งชื่อ _handleButtonClick ที่อยู่ในคอมโพเนนท์ Switcher
1
class Switcher extends React.Component {
2
render() {
3
return (
4
<button onClick={ this._handleButtonClick }>
5
click me
6
</button>
7
);
8
}
9
_handleButtonClick() {
10
console.log('Button is clicked');
11
}
12
};
Copied!
โค้ดชุดนี้จะสามารถทำงานได้ตรงตามที่เราต้องการ เพราะ _handleButtonClick นั้นเป็น function และเราก็ส่ง function เข้าไปใน attribute ชื่อ onClick
แต่!! เนื่องจากตัวโค้ดไม่ได้อยู่ใน context (บริบท) เดียวกัน ส่งผลให้เวลาที่เราต้องการเรียกถึงตัวแปร this ข้างในฟังก์ชัน _handleButtonClick เพื่อเรียกถึงคอมโพเนนท์ Switcher จะทำให้เกิด Error ขึ้นมาทันที
1
class Switcher extends React.Component {
2
constructor(props) {
3
super(props);
4
this.state = { name: 'React in patterns' };
5
}
6
render() {
7
return (
8
<button onClick={ this._handleButtonClick }>
9
click me
10
</button>
11
);
12
}
13
_handleButtonClick() {
14
console.log(`Button is clicked inside ${ this.state.name }`);
15
// ไม่สามารถเรียก this.state.name ได้ เพราะหา this ไม่เจอ เนื่องจาก context ของ this ไม่ตรงกัน
16
// Uncaught TypeError: Cannot read property 'state' of null
17
}
18
};
Copied!
เราสามารถแก้ได้โดยการใช้ bind
1
<button onClick={ this._handleButtonClick.bind(this) }>
2
click me
3
</button>
Copied!
เสียแต่ว่าฟังก์ชัน bind ของเรานั้นจะถูกเรียกซ้ำไปซ้ำมาอยู่บ่อยๆ เพราะว่าคอมโพเนนท์ button อาจถูก render ใหม่หลายๆครั้ง (หรือที่เราเรียกกันว่า re-render) วิธีที่ดีกว่านี้ก็คือการเปลี่ยนไป bind ที่ constructor ของคอมโพเนนท์นั้นทีเดียวเลย
1
class Switcher extends React.Component {
2
constructor(props) {
3
super(props);
4
this.state = { name: 'React in patterns' };
5
// ทำการ binding ที่นี่แทน
6
this._buttonClick = this._handleButtonClick.bind(this);
7
}
8
render() {
9
return (
10
<button onClick={ this._buttonClick }>
11
click me
12
</button>
13
);
14
}
15
_handleButtonClick() {
16
console.log(`Button is clicked inside ${ this.state.name }`);
17
}
18
};
Copied!
Facebook (ผู้สร้าง React) เองก็ยัง แนะนำ เทคนิคเดียวกันนี้เวลาที่ต้องจัดการกับฟังก์ชันที่ใช้ context เดียวกันภายในคอมโพเนนท์
Constructor ยังถือเป็นที่ที่ดีสำหรับการสร้าง handler ที่มีค่าบางอย่างพร้อมแล้วอีกด้วย ยกตัวอย่างเช่น เมื่อเรามี <form> ที่มีหลาย <input> อยู่ข้างใน แต่เราต้องการจัดการการทำงานเมื่อ <input> ถูกเปลี่ยนในฟังก์ชัน _onFieldChange(field, event) เพียงที่เดียว
1
class Form extends React.Component {
2
constructor(props) {
3
super(props);
4
this._onNameChanged = this._onFieldChange.bind(this, 'name');
5
this._onPasswordChanged = this._onFieldChange.bind(this, 'password');
6
}
7
render() {
8
return (
9
<form>
10
<input onChange={ this._onNameChanged } />
11
<input onChange={ this._onPasswordChanged } />
12
</form>
13
);
14
}
15
_onFieldChange(field, event) {
16
console.log(`${ field } changed to ${ event.target.value }`);
17
}
18
};
Copied!

ข้อคิด

การจัดการ event ใน React นั้นอาจดูเหมือนไม่มีอะไรใหม่ให้ศึกษาสักเท่าไหร่ เพราะคนสร้าง React นั้นถือว่าทำไว้ดีแล้วในเรื่องของการนำสิ่งที่มีอยู่แล้วมาใช้ ในเมื่อตัวไลบรารี่เองมีการใช้ syntax ที่เหมือนกับ HTML เดิมอยู่แล้ว จึงไม่ใช่เรื่องแปลกอะไรที่จะมีการจัดการ event เหมือนใน DOM
Last modified 3yr ago
Copy link