W poprzednim wpisie dowiedzieliśmy się czym są propsy i jak dzięki nim możemy reużywać komponenty. W tym zajmniemy się obsługa zdarzeń, czyli jak w React obsłużyć np. kliknięcie na obszarze danego komponentu.
Obsługa zdarzeń w React
Wykonanie kawałka kodu w React po np. kliknięciu komponentu wygląda bardzo podobnie jak w tradycyjnym JavaScript. Po pierwsze w JSX znajdujemy element, który ma nasłuchiwać na zdarzenia i przy pomocy znanego on*, czyli np. onClick, onMouseLeave etc. powiedzieć, na jakie zdarzenie chcemy czekać.
Pozostałe części cyklu:
- Utworzenie projektu i pierwszy komponent
- Komponenty i props
- Obsługa zdarzeń
- Stan komponentu i przepływ danych
- Dynamiczne tworzenie komponentów, key i forumlarz
- Hook useEffect
- Zapisywanie danych w chmurze – Firebase
- Wdrożenie aplikacji na zewnętrznym serwerze – Heroku
Tutorial React w formie wideo dostępny jest na kursy.clockworkjava.pl
export const Image = ({ url }) => { return ( <img src={url} height="175" width="200" onClick=... ></img> ); };
W powyższym przykladzie dodaliśmy w tagach img właściwość onClick, bo chcemy wykonać kawałek logiki, gdy użytkownik kliknie obrazek.
Ten kawałek logiki umieszczamy w nawiasach klamrowych po onClick=. Musi być to funkcja, która może przyjmować jeden argument – będzie to obiekt event z danymi zdarzenia jakie zostało wywołane.
<img src={url} height="175" width="200" onClick={event => console.log(url)} ></img>
Czyli po kliknięciu elementu img w komponencie Image na konsoli zostanie wypisany adres url danego obrazu.
Wszystko pięknie, tylko nie zawsze logika, którą chcemy wykonać zmieści się w kilku tylko znakach. Wówczas warto przenieść funkcję obsługującą dane zdarzenie do osobnej zmiennej.
export const Image = ({ url }) => { const handleOnClick = event => { console.log(url); }; return ( <img src={url} height="175" width="200" onClick={handleOnClick}> </img> ); };
Czyli całość obsługi zdarzenia przypisujemy do zmiennej, a potem podajemy ją jako wartość dla onClick.
Tyle, jeśli chodzi o podstawy, są natomiast dwie sprawy, na które należy zwrócić uwagę pracując z event handlerami.
Gubienie kontekstu, czyli this to nie ten this
Problem ten dotyczy w głównej mierze komponentów klasowych, od których obecnie można w dużej mierze odejść, bo od czasu hooks komponenty funkcyjne mogą mieć własny stan i obsługę zdarzeń cyklu życia, ale to tym w następnym w wpsie.
Nie zmienia to jednak faktu, że warto wiedzieć o problemie z 'this’ przy event handlerach.
Deklarując funkcję obsługującą zdarzenie użyłem arrow function, zamiast klasycznego function(event). Poniżej wersja function vs arrow function.
const hoc = function(event) { console.log(url); } const handleOnClick = event => { console.log(url); };
W naszym przykładzie nie ma to znaczenia, ma natomiast gdybyśmy pracowali z klasami, to przy użyciu function do zdefiniowania funkcji obsługującej event handling zgubilibyśmy kontekst (this).
Arrow function automatycznie łączy daną funkcję z kontekstem, w którym została zdefiniowana.
Dlatego, przeskakując do konkluzji, deklarując funkcję obsługujące zdarzenia warto zawsze używać arrow function zamiast klasycznego podejścia.
Blokowanie domyślnego zachowania
Ważne jest również, by pamiętać o dwóch funkcjach, które powinny być wołane na początku obsługi wydarzenia, mianowicie event.preventDefault() oraz event.stopPropagation().
Do czego one służą?
Część elementów w HTML ma domyślne zachowanie przy pewnych wydarzeniach. Podstawowym przykładem jest kliknięcie elementu button w formularzu. Spowoduje ono przesłanie formularza, a w praktyce przeładowanie strony. Co przy używaniu React jest bardzo niepożądanym zachowaniem. Dlatego na początku funkcji obsługującej zdarzenie warto dodać event.preventDefault() by wyłączyć domyślne zachowanie.
Gdy zmienimy nieco definicję naszego głównego komponentu poprzez dodanie <div> z nasłuchiwaniem na kliknięcie.
export const App = () => { return ( <div onClick={event => console.log("Event from div")}> <Image url="https://images.unsplash.com/photo-1508138221679-760a23a2285b" /> <Image url="https://images.unsplash.com/photo-1474487548417-781cb71495f3" /> <Image url="https://images.unsplash.com/photo-1580109672851-b85640868813" /> <Image url="https://images.unsplash.com/photo-1580046939256-c377c5b099f1" /> <Image url="https://images.unsplash.com/photo-1576801488695-2e4d7a14b8b5" /> </div> ); };
To po kliknięciu obrazu zostanie wywołany event listener zarówno z danego kompnentu Image (czyli wypisze URL na konsolę) ORAZ zostanie wywołany event z div’a, czyli na konsoleęzostanie wypisany też tekst „Event from div”. To zachowanie jest spowodowane tak zwanym 'event propagation’ – zdarzenie wędruję w górę drzewa DOM uruchamiając każdy nasłuchujący na nie event listener.
event.stopPropagation() przerywa propagację. Tak zdefiniowany event listener w Image spowoduję, że pojawi się tylko URL obrazu, a onClick z div’a nie zostanie już uruchomiony.
export const Image = ({ url }) => { const handleOnClick = event => { event.preventDefault(); event.stopPropagation(); console.log(url); }; return <img src={url} height="175" width="200" onClick={handleOnClick}></img>; };
Tyle w temacie obsługi zdarzeń. Nie zrobiliśmy nic w temacie wyglądu czy funkcjonalności strony, ale to się zmieni w przyszłości.
4 komentarze do “Wprowadzenie React #3 (2020) – obsługa zdarzeń”