Tapahtumiin vastaaminen
React antaa sinun lisätä Tapahtumankäsittelijöitä JSX:sssä. Tapahtumankäsittelijät ovat omia funktioitasi, joita kutsutaan vastauksena vuorovaikutuksiin kuten klikkauseen, hoveriin, lomakkeiden kohteiden focusointiin, jne.
Tulet oppimaan
- Eri tavat kirjoittaa Tapahtumankäsittelijä
- Miten välittää Tapahtumankäsittelijän logiikka pääkomponentista
- Miten tapahtumat leviävät ja miten sen voi estää
Tapahtumankäsittelijöiden lisääminen
Lisätäksesi Tapahtumankäsittelijän, täytyy ensiksi määritellä funktio ja sitten välittää se propsina sopivalle JSX tagille. Esimerkiksi, tässä on painike, joka ei tee vielä mitään:
export default function Button() { return ( <button> I don't do anything </button> ); }
Voit laittaa sen näyttämään viestin kun käyttäjä klikkaa tekemällä nämä kolme vaihetta:
- Määritä funktio nimeltään
handleClick
komponentinButton
sisällä. - Toteuta logiikka funktion sisällä (käytä
alert
funktiota näyttääksesi viestin). - Lisää
onClick={handleClick}
<button>
tagiin JSX:ssä.
export default function Button() { function handleClick() { alert('You clicked me!'); } return ( <button onClick={handleClick}> Click me </button> ); }
Määrittelit handleClick
funktion ja välitit sen propsina <button>
:lle. handleClick
on tapahtumaksäittelijä. Tapahtumankäsittelijäfunktiot:
- ovat useimmiten määritelty komponenttien sisällä.
- alkavat sanalla
handle
, jonka jälkeen nimeen tulee tapahtuman nimi.
Tavanomaisesti Tapahtumankäsittelijät alkavat sanalla handle
ja sisältävät tapahtuman nimen. Näet usein onClick={handleClick}
, onMouseEnter={handleMouseEnter}
, ja niin edelleen.
Vaihtoehtoisesti voit määritellä Tapahtumankäsittelijän samalla rivillä JSX:ssä.
<button onClick={function handleClick() {
alert('You clicked me!');
}}>
Tai tiiviimmin nuolifunktioilla:
<button onClick={() => {
alert('You clicked me!');
}}>
Kaikki nämä tyylit vastaavat toisiaan. Samalla rivillä olevat Tapahtumankäsittelijät ovat käteviä lyhyihin funktioihin.
Propsien lukeminen Tapahtumankäsittelijöissä
Sillä Tapahtumankäsittelijät ovat määritelty komponentin sisällä, niillä on pääsy komponenttien propseihin. Tässä on painike, joka klikattaessa näyttää message
prosin ilmoituksena:
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> ); }
Näin nämä kaksi painiketta voivat näyttää eri viestejä. Kokeile muuttaa niille välitettyjä viestejä.
Tapahtumankäsittelijöiden välittäminen propseina
Usein haluat pääkomponentin pystyä määritellä alakomponentin Tapahtumankäsittelijän. Esimerkiksi painikkeet: riippuen missä käytät Button
komponenttia, saatat haluta kutsua eri funktiota. Ehkäpä yksi toistaa videota ja toinen lähettää kuvan palvelimelle.
Voit tehdä tämän välittämällä Tapahtumankäsittelijän propsina alakomponentille:
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> ); }
Tässä, Toolbar
komponentti renderöi PlayButton
komponentin sekä UploadButton
komponentin:
PlayButton
välittäähandlePlayClick
funktiononClick
propsinaButton
:lle.UploadButton
välittää() => alert('Uploading!')
funktiononClick
propsinaButton
:lle.
Lopuksi, Button
komponenttisi hyväksyy onClick
propsin. Se välittää propsin suoraan selaimen sisäänrakennettuun <button>
elementtiin onClick={onClick}
koodilla. Tämä kertoo Reactille, että kutsuu välitettyä funktiota klikkauksen yhteydessä.
Jos käytät design system:iä, on yleistä komponenttien kuten painikkeiden sisältää tyylit mutta ei käyttäytymistä. Sen sijaan komponentit kuten PlayButton
ja UploadButton
välittävät Tapahtumankäsittelijät alaspäin.
Tapahtumankäsittelijän propsien nimeäminen
Sisäänrakennetut elementit kuten <button>
ja <div>
tukevat ainoastaan selaimen tapahtumien nimiä kuten onClick
. Kuitenkin, kun rakennat omia komponenttejasi, voit nimetä niiden Tapahtumankäsittelijöiden propsit miten haluat.
Tavanomaisesti, Tapahtumankäsittelijän propsien kuuluisi alkaa sanalla on
, ja jatkua isolla kirjaimella.
Esimerkiksi, Button
komponentin onClick
propsi voitaisiin kutusua 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> ); }
Tässä esimerkissä, <button onClick={onSmash}>
kertoo, että selaimen <button>
elementti (pienin kirjaimin) tarvitsee silti propsin nimeltään onClick
, mutta kustomoidun Button
komponentin vastaanottaman propsin nimi voi olla mikä tahansa!
Kun komponenttisi tukee useampia interaktioita, saatat nimetä Tapahtumankäsittelijöiden propsit sovelluskohtaisin konseptein. Esimerkiksi tämä Toolbar
komponentti vastaanottaa onPlayMovie
sekä onUploadImage
Tapahtumankäsittelijät:
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> ); }
Huomaa, miten App
komponentin ei tarvitse tietää mitä Toolbar
tekee sen onPlayMovie
tai onUploadImage
Tapahtumankäsittelijöillä. Se on Toolbar
komponentin toteutusyksityiskohta. Tässä, Toolbar
välittää ne Button
:nien onClick
käsittelijöinä, mutta se voisi myöhemmin myös kutsua niitä pikanäppäimestä. Propsien nimeäminen sovelluskohtaisten vuorovaikutusten kautta, kuten onPlayMovie
, antaa joustavuuden muuttaa niitä myöhemmin.
Tapahtuman leviäminen
Komponenttisi tapahtumankäsittelijät nappaavat tapahtumia myös alakomponenteista. Tätä usein kutsutaan “kuplimiseksi” tai “propagoinniksi”: se alkaa sieltä missä tapahtuma esiintyi ja nousee puussa ylemmäs.
Tämä <div>
sisältää kaksi painiketta. Sekä <div>
tagi että painikkeet omaavat ikioman onClick
käsittelijän. Mitä arvelet mitä Tapahtumankäsittelijää kutsutaan, kun painiketta klikataan?
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> ); }
Jos klikkaat jompaa kumpaa painiketta, sen onClick
suoritetaan ensin, jonka jälkeen <div>
tagin onClick
. Joten kaksi viestiä tulee näkyviin. Jos klikkaat työkalupalkkia vain <div>
:n onClick
suoritetaan.
Propagoinnin pysäyttäminen
Tapahtumankäsittelijät vastaanottavat tapahtumaolion niiden ainoana argumenttina. Tavanomaisesti sitä usein kutsutaan e
kirjaimella, joka on lyhenne sanasta “event”. Voit käyttää tätä oliota lukeaksesi tietoa tapahtumasta.
Tämä tapahtumaolio mahdollistaa myös tapahtuman propagoinnin estämisen. Jos haluat estää tapahtuman propagoinnin pääkomponenteille, kutsu e.stopPropagation()
funktiota kuten tämä Button
komponentti tekee:
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> ); }
Kun klikkaat painiketta:
- React kutsuu
<button>
tagille annettuaonClick
käsittelijää. - Tämä
Button
:ssa määritelty käsittelijä tekee seuraavat asiat:- Kutsuu
e.stopPropagation()
funktiota, estäen tapahtuman kuplimisen. - Kutsuu
onClick
funktiota, joka onToolbar
komponentista välitetty propsi.
- Kutsuu
Toolbar
komponentissa määritelty funktio näyttää painikkeen oman ilmoituksen.- Sillä propagointi on pysäytetty,
<div>
taginonClick
käsittelijää ei suoriteta.
e.stopPropagation()
funktion tuloksena painikkeiden klikkaaminen näyttää vain yhden ilmoituksen (button
:sta) kahden ilmoituksen sijaan (<button>
:sta sekä <div>
:sta). Painikkeen klikkaaminen ei ole sama asia kuin ympäröivä työkalupalkki, joten propagoinnin pysäyttäminen on järkevää tälle UI:lle.
Syväsukellus
Harvinaisissa tapauksissa saatat haluta napata kaikki lapsielementtien tapahtumat, vaikka ne olisivat estäneet propagoinnin. Esimerkiksi, ehkäpä haluat kerätä analytiikkatietoja jokaisesta klikkauksesta, riippumatta propagointilogiikasta. Voit tehdä tämän lisäämällä Capture
tapahtumanimen perään:
<div onClickCapture={() => { /* suoritetaan ensin */ }}>
<button onClick={e => e.stopPropagation()} />
<button onClick={e => e.stopPropagation()} />
</div>
Jokainen tapahtuma propagoituu kolmaessa vaiheessa:
- Se kulkee alaspäin, kutsuen kaikki
onClickCapture
käsittelijät. - Se suorittaa klikatun elementin
onClick
käsittelijän. - Se kulkee ylöspäin, kutsuen kaikki
onClick
käsittelijät.
Tapahtumien nappaaminen on kätevää koodille kuten reitittimille taikka analytiikalle, mutta et todennäköisesti tule käyttämään sitä sovelluskoodissa.
Käsittelijöiden välittäminen vaihtoehtona propagoinnille
Huomaa kuinka tämä klikkauskäsittelijä suorittaa yhden rivin koodia ja sitten kutsuu välitettyä onClick
propsia:
function Button({ onClick, children }) {
return (
<button onClick={e => {
e.stopPropagation();
onClick();
}}>
{children}
</button>
);
}
Voisit halutessasi lisätä lisää koodia tähän käsittelijään ennen onClick
Tapahtumankäsittelijän kutsumista. Tämä tapa mahdollistaa vaihtoehdon propagoinnille. Sen avulla alakomponentit käsittelevät tapahtuman, silti antaen pääkomponenttien määritellä lisäkäyttäytymisiä. Toisin kuin propagointi, se ei ole automaattista. Kuitenkin tällä tavalla voit selkeästi seurata koko koodiketjua, jota kutsutaan jonkin tapahtuman seurauksena.
Jos nojaat propagointiin ja on hankalaa jäljittää mikä käsittelijä suoritetaan ja miksi, kokeile tätä tapaa sen sijaan.
Oletustoiminnon estäminen
Jotkin selaintapahtumat sisältävät oletustoimintoja. Esimerkiksi kun <form>
:ssa olevaa painiketta klikataan, submit -tapahtuma lataa koko sivun uudelleen oletusarvoisesti:
export default function Signup() { return ( <form onSubmit={() => alert('Submitting!')}> <input /> <button>Send</button> </form> ); }
Voit kutsua tapahtumaolion e.preventDefault()
funktiota estääksesi tämän tapahtumasta:
export default function Signup() { return ( <form onSubmit={e => { e.preventDefault(); alert('Submitting!'); }}> <input /> <button>Send</button> </form> ); }
Älä sekoita e.stopPropagation()
ja e.preventDefault()
funktioita. Molemmat ovat hyödyllisiä, mutta ne eivät liity toisiinsa:
e.stopPropagation()
estää ylempien tagien käsittelijöiden suorittamisen.e.preventDefault()
estää selaimen oletustoiminnon muutamissa tapahtumissa, joissa sellainen on.
Voiko Tapahtumankäsittelijöillä olla sivuvaikutuksia?
Totta kai! Tapahtumankäsittelijät ovat paras paikka sivuvaikutuksille.
Toisin kuin renderöintifunktiot, Tapahtumankäsittelijöiden ei tarvitse olla puhtaita, joten ne ovat hyvä hyvä paikka muuttaa jotain. Esimerkiksi, syöttökentän arvon muuttaminen kirjoituksen seurauksena, tai listan muuttaminen painikkeen painalluksen seurauksena. Kuitenkin, jotta voit muuttaa jotain tietoa, se täytyy ensiksi tallentaa. Reactissa tämä tapahtuu käyttämällä tilaa, komponentin muistia. Tulet oppimaan siitä kaiken seuraavalla sivulla.
Kertaus
- Voit käsitellä tapahtumia välittämällä funktion propsina elementille kuten
<button>
. - Tapahtumankäsittelijät tulee välitää, ei kutsua!
onClick={handleClick}
, eionClick={handleClick()}
. - Voit määritellä Tapahtumankäsittelijän funktion erikseen tai samalla rivillä.
- Tapahtumankäsittelijät määritellään komponentin sisällä, jotta ne saavat pääsyn propseihin.
- Voit määritellä Tapahtumankäsittelijän yläkomponentissa ja välittää sen propsina alakomponentille.
- Voit määritellä omian Tapahtumankäsittelijäpropseja sovelluskohtaisilla nimillä.
- Tapahtumat propagoituvat ylöspäin. Kutsu
e.stopPropagation()
estääksesi sen. - Tapahtumilla saattaa olla ei toivottuja oletustoimintoja. Kutsu
e.preventDefault()
estääksesi sen. - Tapahtumankäsittelijän kutsuminen alakomponentista on hyvä vaihtoehto propagoinnille.
Haaste 1 / 2: Korjaa Tapahtumankäsittelijä
Painikkeen painamisen on tarkoitus vaihtaa sivun taustaväriä valkoisen ja musta välillä. Klikattaessa mitään ei kuitenkaan tapahdu. Korjaa ongelma. (Älä huoli handleClick
:n sisällä olevasta logiikasta, se on hyvä sellaisenaan.)
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()}> Kytke valot </button> ); }