react obsługa zdarzeń

Wprowadzenie React #3 (2020) – obsługa zdarzeń

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:

  1. Utworzenie projektu i pierwszy komponent
  2. Komponenty i props
  3. Obsługa zdarzeń
  4. Stan komponentu i przepływ danych
  5. Dynamiczne tworzenie komponentów, key i forumlarz
  6. Hook useEffect
  7. Zapisywanie danych w chmurze – Firebase

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.

Kod przykładu dostępny jest na Github.

Tradycyjnie zapraszam do dołączenia do newslettera, gdzie materiały odnośnie React również mają swoje miejsce.

4 myśli w temacie “Wprowadzenie React #3 (2020) – obsługa zdarzeń”

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *