ການ Respond ຕໍ່ Events
React ໃຫ້ທ່ານເພີ່ມ event handlers ໃນ JSX ຂອງທ່ານ. Event handler ແມ່ນຟັງຊັ່ນຂອງທ່ານເອງທີ່ຈະຖືກ trigger ໃຫ້ຕອບສະໜອງຕໍ່ interaction ເຊັ່ນ ການຄິກ, ການ hover, ການ focus form input ແລະ ອື່ນໆ.
You will learn
- ວິທີຕ່າງໆໃນການຂຽນ event handler
- ວິທີການສົ່ງຜ່ານ logic ຂອງ event handler ຈາກ parent component
- Event ກະຈາຍແນວໃດ ແລະ ຈະຢຸດແນວໃດ
ການເພີ່ມ event handlers
ໃນການເພີ່ມ event handler, ທຳອິດທ່ານຈະຕ້ອງກຳນົດຟັງຊັ່ນ ຈາກນັ້ນ ສົ່ງຜ່ານເປັນ prop ໄປຫາແທັກ JSX ທີ່ເໝາະສົມ. ຕົວຢ່າງ, ນີ້ແມ່ນປຸ່ມທີ່ຍັງບໍ່ທັນໄດ້ເຮັດຫຍັງ:
export default function Button() { return ( <button> I don't do anything </button> ); }
ທ່ານສາມາດກຳນົດໃຫ້ສະແດງຂໍ້ຄວາມເມື່ອຜູ້ໃຊ້ຄິກໂດຍປະຕິບັດຕາມສາມຂັ້ນຕອນ:
- ປະກາດຟັງຊັ່ນທີ່ເອີ້ນວ່າ
handleClick
ພາຍໃນ componentButton
ຂອງທ່ານ. - Implement logic ພາຍໃນຟັງຊັ່ນນັ້ນ (ໃຊ້
alert
ເພື່ອສະແດງຂໍ້ຄວາມ). - ເພີ່ມ
onClick={handleClick}
ໃນ<button>
JSX.
export default function Button() { function handleClick() { alert('You clicked me!'); } return ( <button onClick={handleClick}> Click me </button> ); }
ທ່ານກຳນົດຟັງຊັ່ນ handleClick
ຈາກນັ້ນ ສົ່ງຜ່ານເປັນ prop ເປັນ <botton>
. handleClick
ເປັນ event handler. ຟັງຊັ່ນ Event handler:
- ມັກຖືກກຳນົດ ພາຍໃນ component ຂອງທ່ານ.
- ມີຊື່ຂຶ້ນຕົ້ນດ້ວຍ
handle
, ຕາມດ້ວຍຊື່ event.
ຕາມແບບແຜນ, ມັນເປັນເລື່ອງປົກະຕິທີ່ຈະຕັ້ງຊື່ event handler ເປັນ handle
ຕາມດ້ວຍຊື່ event. ທ່ານມັກຈະເຫັນ onClick={handleClick}
, onMouseEnter={handleMouseEnter}
, ແລະ ອື່ນໆ
ຫຼື ທ່ານສາມາດກຳນົດ event handler ແບບແຖວດຽວໃນ JSX:
<button onClick={function handleClick() {
alert('You clicked me!');
}}>
ຫຼື, ກະຊັບຫຼາຍຂຶ້ນ, ດ້ວຍການໃຊ້ arrow function:
<button onClick={() => {
alert('You clicked me!');
}}>
ຮູບແບບທັງໝົດນີ້ແມ່ນຄືກັນ. Event handler ແບບແຖວດຽວແມ່ນສະດວກສຳລັບຟັງຊັ່ນສັ້ນໆ.
ການອ່ານ props ໃນ event handlers
ເນື່ອງຈາກມີການປະກາດ event handler ພາຍໃນ component, ພວກມັນຈຶ່ງສາມາດເຂົ້າເຖິງ prop ຂອງ component. ນີ້ແມ່ນປຸ່ມທີ່, ເມື່ອທ່ານຄິກແລ້ວ, ຈະສະແດງການແຈ້ງເຕືອນພ້ອມກັບ message
prop:
function AlertButton({ message, children }) { return ( <button onClick={() => alert(message)}> {children} </button> ); } export default function Toolbar() { return ( <div> <AlertButton message="Playing!"> Play Movie </AlertButton> <AlertButton message="Uploading!"> Upload Image </AlertButton> </div> ); }
ເຊິ່ງຈະເຮັດໃຫ້ປຸ່ມທັງສອງນີ້ສະແດງຂໍ້ຄວາມທີ່ແຕກຕ່າງກັນໄດ້. ລອງປ່ຽນຂໍ້ຄວາມທີ່ສົ່ງເຖິງພວກມັນ.
ການສົ່ງ event handlers ເປັນ props
ຫຼາຍເທື່ອທີ່ທ່ານຕ້ອງການໃຫ້ parent component ລະບຸ child event handler. ຂຶ້ນຢູ່ກັບປຸ່ມ: ຂຶ້ນຢູ່ກັບວ່າທ່ານໃຊ້ component Button
ບ່ອນໃດ, ທ່ານອາດຈ້ອງ execute ຟັງຊັ່ນອື່ນ ບາງເທື່ອຟັງຊັ່ນໜຶ່ງຫຼິ້ນວີດີໂອ ແລະ ອີກຟັງຊັ່ນໜໜຶ່ງອັບໂຫຼດຮູບພາບ.
ເພື່ອເຮັດສິ່ງນີ້, ໃຫ້ສົ່ງ prop ທີ່ component ໄດ້ຮັບຈາກ parent ເປັນ event handler ດັ່ງນີ້:
function Button({ onClick, children }) { return ( <button onClick={onClick}> {children} </button> ); } function PlayButton({ movieName }) { function handlePlayClick() { alert(`Playing ${movieName}!`); } return ( <Button onClick={handlePlayClick}> Play "{movieName}" </Button> ); } function UploadButton() { return ( <Button onClick={() => alert('Uploading!')}> Upload Image </Button> ); } export default function Toolbar() { return ( <div> <PlayButton movieName="Kiki's Delivery Service" /> <UploadButton /> </div> ); }
ຈຸດນີ້, component Toolbar
ທຳການ render PlayButton
ແລະ UploadButton
:
PlayButton
ສົ່ງhandlePlayClick
ເປັນ proponClick
ໄປຍັງButton
ພາຍໃນ.UploadButton
ສົ່ງ() => alert('Uploading!')
ເປັນ prop ໄປຍັງButton
ພາຍໃນ.
ສຸດທ້າຍ, component Button
ຂອງທ່ານພ້ອມຮັບ prop ທີ່ຊື່ວ່າ onClick
. ມັນສົ່ງຜ່ານ prop ໂດຍກົງໄປຫາ built-in browser <button>
ດ້ວຍ onClick={onClick}
. ສິ່ງນີ້ຈະບອກໃຫ້ React ເອີ້ນໃຊ້ຟັງຊັ່ນທີ່ສົ່ງຜ່ານເມື່ອຄິກ.
ຖ້າທ່ານໃຊ້ design system, ເປັນເລື່ອງປົກະຕິທີ່ component ຕ່າງໆເຊັ່ນ ປຸ່ມຈະປະກອບມີ style ແຕ່ບໍ່ໄດ້ລະບຸລັກສະນະການເຮັດວຽກ. Component ເຊັ່ນ PlayButton
ແລະ UploadButton
ຈະສົ່ງ event handler ລົງມາແທນ.
ການຕັ້ງຊື່ prop event handler
Component built-in ເຊັ່ນ <button>
ແລະ <div>
ຮອງຮັບສະເພາະ browser event names ເຊັ່ນ onClick
. ເຖິງຢ່າງໃດກໍຕາມ, ເມື່ອທ່ານສ້າງ component ຂອງທ່ານເອງ, ທ່ານສາມາດຕັ້ງຊື່ prop event handler ໄດ້ຕາມທີ່ທ່ານຕ້ອງການ.
ຕາມແບບແຜນ, prop event handler ຄວນເລີ່ມຕົ້ນດ້ວຍ on
, ຕາມດ້ວຍໜັງສືໂຕໃຫຍ່.
ຕົວຢ່າງ, prop onClick
ຂອງ component Button
ອາດຈະຖືກເອີ້ນ onSmash
:
function Button({ onSmash, children }) { return ( <button onClick={onSmash}> {children} </button> ); } export default function App() { return ( <div> <Button onSmash={() => alert('Playing!')}> Play Movie </Button> <Button onSmash={() => alert('Uploading!')}> Upload Image </Button> </div> ); }
ໃນຕົວຢ່າງນີ້, <button onClick={onSmash}>
ສະແດງວ່າ browser <button>
(ໂຕພິມນ້ອຍ) ຍັງຕ້ອງການ prop ຊື່ onClick
, ແຕ່ຊື່ prop ທີ່ໄດ້ຮັບຈາກ component Button
ທີ່ທ່ານກຳນົດເອງແມ່ນຂຶ້ນກັບທ່ານ!
ເມື່ອ component ຂອງທ່ານຮອງຮັບຫຼາຍ interaction, ທ່ານອາດຕັ້ງຊື່ prop event handler ສຳລັບແນວຄິດສະເພາະແອັບ. ຕົວຢ່າງ, component Toolbar
ນີ້ໄດ້ຮັບ event handler onPlayMovie ແລະ
onUploadImage`:
export default function App() { return ( <Toolbar onPlayMovie={() => alert('Playing!')} onUploadImage={() => alert('Uploading!')} /> ); } function Toolbar({ onPlayMovie, onUploadImage }) { return ( <div> <Button onClick={onPlayMovie}> Play Movie </Button> <Button onClick={onUploadImage}> Upload Image </Button> </div> ); } function Button({ onClick, children }) { return ( <button onClick={onClick}> {children} </button> ); }
ສັງເກດວ່າ component App
ບໍ່ຈຳເປັນຕ້ອງຮູ້ວ່າ ສິ່ງທີ່ Toolbar
ຈະເຮັດຫຍັງກັບ onPlayMovie
ຫຼື onUploadImage
. ນັ້ນແມ່ນລາຍລະອຽດການ implementation ຂອງ Toolbar
. ໃນນີ້, Toolbar
ສົ່ງຜ່ານ onClick
handler ໄປຍັງ Button
ຂອງມັນ, ແຕ່ພາຍຫຼັງຍັງສາມາດ trigger ເທິງທາງລັດຄີບອດ. ການຕັ້ງຊື່ prop ຕາມການ interaction ສະເພາະແອັບເຊັ່ນ onPlayMovie
ຊ່ວຍໃຫ້ທ່ານປ່ຽນວິທີໃຊ້ງານໃນພາຍຫຼັງໄດ້ຢ່າງຍືດຫຍຸ່ນ.
ການເຜີຍແຜ່ Event
Event handler ຈະຈັບ event ຈາກ children ທີ່ component ຂອງທ່ານທີ່ອາດມີ. ພວກເຮົາເວົ້າວ່າ event “bubbles” ຫຼື “propagates” ຂຶ້ນໄປເທິງ tree: ມັນເລີ່ມຈາກຈຸດທີ່ event ນັ້ນເກີດຂຶ້ນ, ຈາກນັ້ນຈຶ່ງຂຶ້ນໄປເທິງ tree.
<div>
ປະກອບມີສອງປຸ່ມ. ທັງ <div>
ແລະ ແຕ່ລະປຸ່ມມີ onClick
handler ຂອງໂຕເອງ. ທ່ານຄິດວ່າ handler ໃດທີ່ຈະເລີ່ມເຮັດວຽກເມື່ອທ່ານຄິກ?
export default function Toolbar() { return ( <div className="Toolbar" onClick={() => { alert('You clicked on the toolbar!'); }}> <button onClick={() => alert('Playing!')}> Play Movie </button> <button onClick={() => alert('Uploading!')}> Upload Image </button> </div> ); }
ຖ້າທ່ານຄິກປຸ່ມໃດໜຶ່ງ, onClick
ຈະເຮັດວຽກກ່ອນ, ຕາມດ້ວຍ onClick
ຂອງ parent <div>
. ສະນັ້ນສອງຂໍ້ຄວາມຈະປະກົດຂຶ້ນ. ຖ້າທ່ານຄິກ toolbar, ສະເພາະ onClick
ຂອງ <div>
ຂອງ parent ເທົ່ານັ້ນທີ່ຈະເຮັດວຽກ
ຢຸດການເຜີຍແຜ່
Event handler ຮັບ event object ເປັນ argument ພຽງຢ່າງດຽວ. ໂດຍທົ່ວໄປ, ຈະເອີ້ນວ່າ e
, ທີ່ຫຍໍ້ມາຈາກ “event”. ທ່ານສາມາດໃຊ້ object ນີ້ເພື່ອອ່ານຂໍ້ມູນກ່ຽວກັບ event.
Event object ນັ້ນຍັງຊ່ວຍໃຫ້ທ່ານຢຸດການເຜີຍແຜ່. ຫາກທ່ານຕ້ອງການປ້ອງກັນບໍ່ໃຫ້ event ເຂົ້າເຖິງ parent component, ທ່ານຕ້ອງເອີ້ນໃຊ້ e.stopPropagation()
ຄືກັບ component Button
ເຮັດ:
function Button({ onClick, children }) { return ( <button onClick={e => { e.stopPropagation(); onClick(); }}> {children} </button> ); } export default function Toolbar() { return ( <div className="Toolbar" onClick={() => { alert('You clicked on the toolbar!'); }}> <Button onClick={() => alert('Playing!')}> Play Movie </Button> <Button onClick={() => alert('Uploading!')}> Upload Image </Button> </div> ); }
ເມື່ອທ່ານຄິກທີ່ປຸ່ມ:
- React ເອີ້ນໃຊ້
onClick
handler ທີ່ສົ່ງຜ່ານໄປຍັງ<button>
. - Handler, ຖືກກຳນົດໃນ
Button
, ເຮັດສິ່ງຕໍ່ໄປນີ້:- ເອີ້ນ
e.stopPropagation()
, ເພື່ອປ້ອງກັນບໍ່ໃຫ້ event ເດືອດອີກຕໍ່ໄປ. - ເອີ້ນໃຊ້ຟັງຊັ່ນ
onClick
, ເຊິ່ງເປັນ prop ທີ່ສົ່ງຜ່ານຈາກ componentToolbar
- ເອີ້ນ
- ຟັງຊັ່ນນັ້ນເຊິ່ງກຳນົດໄວ້ໃນ component
Toolbar
, ສະແດງການແຈ້ງເຕືອນຂອງປຸ່ມເອງ. - ເນື່ອງຈາກການເຜີດແຜ່ຢຸດລົງ,
onClick
handler ຂອງ parent<div>
ຈຶ່ງ ບໍ່ ເຮັດວຽກ.
ຈາກຜົນຂອງ e.stopPropagation()
, ຕອນນີ້ການຄິກທີ່ປຸ່ມຈະສະແດງພຽງການແຈ້ງເຕືອນດຽວ (ຈາກ <button>
) ແທນທີ່ຈະເປັນສອງປຸ່ມ (ຈາກ <botton>
ແລະ parent toobar <div>
). ການຄິກປຸ່ມບໍ່ຄືກັບການຄິກ toolbar ຮອບໆ, ສະນັ້ນການຢຸດເຜີຍແຜ່ຈິງເໝາະສົມສຳລັບ UI ນີ້.
Deep Dive
ໃນກໍລະນີທີ່ເກີດຂຶ້ນບໍ່ຫຼາຍ, ທ່ານອາດຈະຕ້ອງ catch event ທັງໝົດໃນ child element, ເຖິງວ່າເຫດການເຫຼົ່ານັ້ນຈະຢຸດເຜີຍແຜ່ໄປແລ້ວກໍຕາມ. ຕົວຢ່າງ, ບາງທີທ່ານອາດຕ້ອງການບັນທຶກທຸກການຄິກໄປຍັງການວິເຄາະ ໂດຍບໍ່ຄຳນຶງ logic ການເຜີຍແຜ່. ທ່ານສາມາດເຮັດໄດ້ໂດຍເພີ່ມ Capture
ຕໍ່ທ້າຍຊື່ event:
<div onClickCapture={() => { /* this runs first */ }}>
<button onClick={e => e.stopPropagation()} />
<button onClick={e => e.stopPropagation()} />
</div>
ແຕ່ລະ event ເຜີຍແຜ່ໃນສາມຂັ້ນຕອນ:
- ມັນເຄື່ອນລົງມາ, ໂດຍການເອີ້ນ
onClickCapture
handler. - ມັນແລ່ນ
onClick
handler ຂອງ element ການຄິກ. - ມັນເຄື່ອນທີ່ຂຶ້ນທາງເທິງ, ເອີ້ນ
onClick
handler ທັງໝົດ.
Event Capture ມີປະໂຫຍດສຳລັບ code ເຊັ່ນ router ຫຼື ການວິເຄາະ, ແຕ່ທ່ານອາດບໍ່ແມ່ນ event ເຫຼົ່ານັ້ນໃນ code ຂອງແອັບ.
ການສົ່ງ handler ເປັນທາງເລືອກໃນການເຜີຍແຜ່
ສັງເກດວ່າ click handler ນີ້ແລ່ນ code ແລ້ວ ເອີ້ນ prop onClick
ທີ່ parent ສົ່ງໄດ້ແນວໃດ:
function Button({ onClick, children }) {
return (
<button onClick={e => {
e.stopPropagation();
onClick();
}}>
{children}
</button>
);
}
ທ່ານສາມາດເພີ່ມ code ໃຫ້ກັບ handler ນີ້ກ່ອນທີ່ຈະເອີ້ນ event handler onClick
parent ໄດ້, ຄືກັນ. ຮູບແບບນີ້ໃຫ້ ທາງເລືອກ ໃນການເຜີຍແຜ່. ມັນອະນຸຍາດໃຫ້ child component ຈັດການ event, ໃນຂະນະທີ່ຍັງໃຫ້ parent component ລະບຸພຶດທິກຳເພີ່ມເຕີມບາງຢ່າງ. ບໍ່ຄືກັບການເຜີຍແຜ່, ມັນບໍ່ອັດຕະໂນມັດ. ແຕ່ຂໍ້ດີຂອງຮູບແບບນີ້ຄືທ່ານສາມາດຕິດຕາມຕ່ອງໂສ່ຂອງ code ທັງໝົດໄດ້ຢ່າງຊັດເຈນເຊິ່ງງດຳເນີນການໂດຍເປັນຜົນມາຈາກ event ບາງຢ່າງ.
ຖ້າທ່ານເພິ່ງພາການເຜີຍແຜ່ ແລະ ເປັນການຍາກທີ່ຈະຕິດຕາມວ່າ handler ໃດ execute ແລະ ຍ້ອນຫຍັງ, ໃຫ້ລອງໃຊ້ວິທີນີ້ແທນ.
ການປ້ອງກັນພຶດທິກຳເລີ່ມຕົ້ນ
Event ບາວເຊີບາງຢ່າງມີລັກສະນະການເຮັດວຽກເລີ່ມຕົ້ນທີ່ກ່ຽວຂ້ອງ. ຕົວຢ່າງ, event ການ submit <form>
, ເຊິ່ງເກີດຂຶ້ນເມື່ອທ່ານຄິກປຸ່ມພາຍໃນນັ້ນ, ຈະໂຫຼດໜ້າໃໝ່ຕາມຄ່າເລີ່ມຕົ້ນ:
export default function Signup() { return ( <form onSubmit={() => alert('Submitting!')}> <input /> <button>Send</button> </form> ); }
ທ່ານສາມາດເອີ້ນ e.preventDefault()
ເທິງ event object ເພື່ອຢຸດສິ່ງນີ້ບໍ່ໃຫ້ເກີດຂຶ້ນ:
export default function Signup() { return ( <form onSubmit={e => { e.preventDefault(); alert('Submitting!'); }}> <input /> <button>Send</button> </form> ); }
ຢ່າສັບສົນລະຫວ່າງ e.stopPropagation()
ແລະ e.preventDefault()
. ມີປະໂຫຍດໝົດສອງ, ແຕ່ບໍ່ກ່ຽວຂ້ອງກັນ:
e.stopPropagation()
ຢຸດ event handler ທີ່ແນບກັບແທັກທາງເທິງບໍ່ໃຫ້ເລີ່ມເຮັດວຽກ.e.preventDefault()
ປ້ອງກັນພຶດທິກຳເລີ່ມຕົ້ນຂອງບາວເຊີສຳລັບບາງ event ທີ່ມີ.
Event handler ສາມາດມີ່ຜົນຂ້າງຄຽງໄດ້ ຫຼື ບໍ່?
ແນ່ນອນ! Event handler ເປັນບ່ອນທີ່ດີທີ່ສຸດສຳລັບຜົນຂ້າງຄຽງ.
Event handler ບໍ່ຈຳເປັນຕ້ອງ pure, ເຊິ່ງແຕກຕ່າງຈາກຟັງຊັ່ນການ render, ດັ່ງນັ້ນມັນຈຶ່ງເປັນບ່ອນທີ່ດີໃນການ ປ່ຽນແປງ ບາງຢ່າງ-ຕົວຢ່າງ, ປ່ຽນຄ່າ input ຕາມການພິມ, ຫຼື ປ່ຽນລາຍການຕາມການກົດປຸ່ມ. ເຖິງຢ່າງໃດກໍຕາມ, ໃນການປ່ຽນແປງຂໍ້ມູນບາງຢ່າງ, ທຳອິດທ່ານຕ້ອງມີວິທີໃນການຈັດເກັບ. ໃນ React, ສິ່ງນີ້ເຮັດໄດ້ໂດຍການໃຊ້ state, memory ຂອງ component. ທ່ານຈະໄດ້ຮຽນຮູ້ທັງໝົດກ່ຽວກັບມັນໃນໜ້າຕໍ່ໄປ.
Recap
- ທ່ານສາມາດ handle event ໂດຍສົ່ງຟັງຊັ່ນເປັນ prop ໄປຫາ element ເຊັ່ນ
<button>
. - Event handler ຕ້ອງຜ່ານ, ບໍ່ເອີ້ນ!
onClick={handleClick}
, ບໍ່ແມ່ນonClick={handleClick}
. - ທ່ານສາມາດກຳນົດຟັງຊັ່ນ event handler ແຍກກັນ ຫຼື ໃນແຖວ.
- Event handler ແມ່ນຖືກກຳນົດໄວ້ໃນ component, ດັ່ງນັ້ນມັນຈຶ່ງສາມາດເຂົ້າເຖິງ prop ໄດ້.
- ທ່ານສາມາດປະກາດ event handler ໃນ parent ແລະ ສົ່ງຕໍ່ເປັນ prop ໄປຫາ child.
- ທ່ານສາມາດກຳນົດ event ຂອງທ່ານເອງດ້ວຍຊື່ສະເພາະຂອງແອັບພິເຄຊັ່ນ.
- Event ເຜີຍແຜ່ຂຶ້ນໄປ. ເອີ້ນວ່າ
e.stopPropagation()
ໃນ argument ທຳອິດເພື່ອປ້ອງກັນສິ່ງນັ້ນ. - Event ອາດມີພຶດທິກຳເລີ່ມຕົ້ນຂອງບາວເຊີທີ່ບໍ່ຕ້ອງການ. ເອີ້ນ
e.preventDefault()
ເພື່ອຫຼີກຫຼ່ຽງມັນ. - ການເອີ້ນ event handler ຢ່າງຊັດເຈນຈາກ child handler ແມ່ນເປັນທາງເລືອກທີ່ດີໃນການເຜີຍແຜ່.
Challenge 1 of 2: ແປງ event handler
ການຄິກປຸ່ມນີ້ຄວນເປັນການສະຫຼັບພື້ນຫຼັງຂອງໜ້າລະຫວ່າງສີຂາວ ແລະ ສີດຳ. ເຖິງຢ່າງໃດກໍຕາມ, ຈະບໍ່ມີຫຍັງເກີດຂຶ້ນເມື່ອທ່ານຄິກມັນ. ແກ້ໄຂບັນຫາ. (ຢ່າກັງວົນກ່ຽວກັບ logic ພາຍໃນ handleClick
-ສ່ວນນັ້ນເຮັດວຽກໄດ້.)
export default function LightSwitch() { function handleClick() { let bodyStyle = document.body.style; if (bodyStyle.backgroundColor === 'black') { bodyStyle.backgroundColor = 'white'; } else { bodyStyle.backgroundColor = 'black'; } } return ( <button onClick={handleClick()}> Toggle the lights </button> ); }