szczecinski.eu

szczecinski.eu

  • Kurs React
  • Zaawansowany React
  • Kurs Redux
  • Kurs ES6
  • Blog
  • Kontakt

›Hooks

Wprowadzenie

  • Tematy zaawansowane

Strukturowanie komponentów

  • Komponenty złożone
  • HoC - Komponenty wyższego rzędu
  • Render Props

Context

  • Wprowadzenie
  • Przykład zastosowania: system translacji
  • Zaawansowane opcje

Hooks

  • Wprowadzenie
  • useState
  • useReducer
  • useEffect
  • useContext
  • Pozostałe hooki
  • Własne hooki

Pozostałe API

  • React.memo
  • React.lazy

Własne hooki

React umożliwia także tworzenie własnych Hooków, dzięki czemu jesteśmy w stanie usunąć logikę z naszych komponentów - będą one odpowiedzialne tylko za wygląd UI - i współdzielić ją między wieloma komponentami. Hooki takie możemy również udostępniać tak samo jak inne aplikacje / komponenty np. za pomocą npm. Dużą kolekcję Hooków stworzonych przez użytkowników React znajdziecie na stronie useHooks.com.

Tworzenie własnych Hooków

W celu utworzenia własnego Hooku musimy zadeklarować go jako funkcja zaczynająca się od słowa use - w ten sposób React odróżnia Hooki od zwykłych funkcji i zapewnia, że wszystkie związane z nimi mechanizmy będą działać poprawnie.

Hooki są też drugim z miejsc, w którym możemy wywoływać inne Hooki, dzięki czemu mogą one np. zawierać swój własny stan, albo efekty.

Przykład 1: Pobieranie danych

Utwórzmy zatem prostą aplikację, wyświetlającą wszystkie Githubowe repozytoria użytkownika:

const InputForm = props => {
  const [value, setValue] = useState("");
  return (
    <div>
      <input value={value} onChange={e => setValue(e.target.value)} />
      <button disabled={!value} onClick={() => props.onSubmit(value)}>
        Szukaj
      </button>
    </div>
  );
};

const App = () => {
  const [userName, setUsername] = useState("");
  const [repositories, setRepositories] = useState([]);
  useEffect(
    () => {
      if (!userName) return;
      fetch(`https://api.github.com/users/${userName}/repos`)
        .then(response => response.json())
        .then(repositories => {
          setRepositories(repositories);
        });
    },
    [userName]
  );

  return (
    <div>
      <InputForm onSubmit={setUsername} />
      <ul>
        {repositories.map(item => (
          <li key={item.full_name}>{item.full_name}</li>
        ))}
      </ul>
    </div>
  );
};

Opierając się na naszych dotychczasowych informacjach, utworzyliśmy oddzielny komponent przechowujący nazwę użytkownika i oddzielny, odpowiedzialny za logikę pobierania i wyświetlania danych. Rozwiązanie takie jest niestety mało elastyczne - jeżeli potrzebowalibyśmy wyświetlać dane w innej formie lub w innym komponencie konieczne było by kopiowanie tam całego kodu useEffect i skojarzonego z nim stanu.

Rozwiązujemy to wprowadzając nowy, własny Hook - useGithub:

const useGithub = () => {
  const [userName, setUsername] = useState("");
  const [repositories, setRepositories] = useState([]);

  useEffect(
    () => {
      if (!userName) return;
      fetch(`https://api.github.com/users/${userName}/repos`)
        .then(response => response.json())
        .then(repositories => {
          setRepositories(repositories);
        });
    },
    [userName]
  );

  return [setUsername, repositories];
};

const App2 = () => {
  const [doSearch, repositories] = useGithub();
  return (
    <div>
      <InputForm onSubmit={doSearch} />
      <ul>
        {repositories.map(item => (
          <li key={item.full_name}>{item.full_name}</li>
        ))}
      </ul>
    </div>
  );
};

Teraz nasz komponent App nie jest już w żaden sposób obarczony logiką pobierania danych z Github - w każdym momencie możemy podmienić wewnętrzną logikę useGithub oraz współdzielić ją z innymi komponentami / Hookami.

Przykład 2: Obsługa formularzy

inny przydatny przykład, to Hook pozwalający na łatwą obsługę pól formularza, np. aby utworzyć re-używalnego Hooka dla pól tekstowych (numerycznych, email etc.):

const useInput = defaults => {
  const [value, updater] = useState(defaults.value || "");

  return {
    props: {
      type: "text",
      ...defaults,
      onChange: e => updater(e.target.value)
    },
    value
  };
};

const App = () => {
  const name = useInput({
    placeholder: "Wpisz imię",
    required: true
  });
  const email = useInput({
    type: "email",
    placeholder: "Wpisz swój e-mail",
    required: true
  });
  return (
    <form onSubmit={_ => false}>
      <input {...name.props} />
      <input {...email.props} />
      <p>
        Wpisana wartość: {name.value} {email.value}
      </p>
      <input type="submit" />
    </form>
  );
};

Utworzony w ten sposób Hook pozwala na opisanie wartości domyślnych dla elementu <input />. Zwracana przez niego wartość, to obiekt, zawierający wartość pola, oraz obiekt atrybutów, które powinniśmy przekazać do naszego elementu HTML. Oczywiście rozszerzenie Hooka o obsługę pól typu checkbox czy radio jest również możliwe.

Kompletny przykład

← Pozostałe hookiReact.memo →
  • Tworzenie własnych Hooków
    • Przykład 1: Pobieranie danych
    • Przykład 2: Obsługa formularzy
  • Kompletny przykład
Bartosz Szczeciński © 2019 Materiał dostępny na zasadach licencji MIT.