React Custom Hooks

7 React Custom Hooks, die ich in meinen Projekten brauche

Die funktionale Programmierparadigma von React hat die Front-End-Entwicklung revolutioniert, indem es das Erstellen von wieder verwendbarem und modularen Code erheblich erleichtert. Eine der mächtigsten Funktionen von React ist die Fähigkeit, eigene Hooks zu erstellen. Diese React Custom Hooks helfen dabei, Logik zu kapseln, den Zustand zu verwalten und komplexe Funktionalitäten in wieder verwendbare Einheiten zu abstrahieren. Dadurch können Entwickler effizienteren, saubereren und besser wartbaren Code schreiben. In React-Anwendungen sind benutzerdefinierte Hooks besonders nützlich, da sie nicht nur die Lesbarkeit des Codes verbessern, sondern auch die Wiederverwendbarkeit und Testbarkeit von Logik über verschiedene Komponenten hinweg ermöglichen. Diese Funktion ermöglicht es Entwicklern, sich auf das Wesentliche zu konzentrieren und die Wiederholung von Code zu vermeiden.

Lasst uns nun einige der häufigsten benutzerdefinierten Hooks untersuchen, die Entwickler in React-Projekten verwenden, und lernen, wie man sie effektiv implementiert. Wir werden dabei Beispiele für verschiedene Szenarien durchgehen, wie etwa die Verwaltung von lokalen Speicherdaten, das Abrufen von Daten über APIs, die Handhabung von Benutzereingaben und vieles mehr. Indem wir diese Techniken verstehen und anwenden, können wir die Flexibilität und Modularität unserer React-Anwendungen erheblich steigern.

Warum benutzerdefinierte Hooks?

Benutzerdefinierte Hooks:

  • Fördern die Wiederverwendbarkeit von Code: Mit benutzerdefinierten Hooks können Entwickler häufig genutzte Logik in separate Funktionen auslagern, die in verschiedenen Komponenten wiederverwendet werden können, ohne sie jedes Mal neu schreiben zu müssen.
  • Vereinfachen komplexe Logik: Indem komplexe Logik aus der Hauptkomponente herausgenommen wird, können benutzerdefinierte Hooks helfen, den Code zu strukturieren und so leichter verständlich zu machen.
  • Verbessern die Lesbarkeit und Wartbarkeit: Wenn Logik in benutzerdefinierte Hooks ausgelagert wird, wird der Hauptcode der Komponenten klarer und fokussierter, was die Lesbarkeit und Wartbarkeit erheblich steigert.
  • Fördern das DRY-Prinzip (Don’t Repeat Yourself): Durch die Schaffung wieder verwendbarer Einheiten können Entwickler Code-Duplikationen vermeiden, was zu einem sauberen und effizienten Code führt.

Mit diesen Vorteilen im Hinterkopf, werfen wir einen Blick auf einige unverzichtbare React Custom Hooks, die du in deinem React-Werkzeugkasten haben solltest. Diese Hooks können dir helfen, gängige Entwicklungsaufgaben effizienter und eleganter zu lösen und gleichzeitig deine Anwendung skalierbarer zu machen.

useFetch: API-Aufrufe vereinfachen

Das Abrufen von Daten ist eine häufige Aufgabe in React-Anwendungen. Der useFetch-Hook abstrahiert den Boilerplate-Code und macht API-Aufrufe eleganter und leichter verständlich.

Mit useFetch kannst du API-Anfragen in einem benutzerdefinierten Hook kapseln, wodurch der Code in deinen Komponenten sauberer wird und du dich auf die Logik der Anwendung konzentrieren kannst, anstatt immer wieder den gleichen Code für die Datenbeschaffung zu schreiben. Dieser Hook hilft nicht nur, die wiederholte Schreibarbeit zu reduzieren, sondern bietet auch eine klare Trennung von Zuständigkeiten, sodass du einfachere und wartbarere Komponenten erstellen kannst.

Ein weiterer Vorteil des useFetch-Hooks ist, dass du ihn an verschiedenen Stellen in deiner Anwendung wiederverwenden kannst, ohne die API-Anruf-Logik erneut implementieren zu müssen. Außerdem kann der Hook mit Zuständen wie „laden“ und „Fehler“ umgehen, was ihn besonders nützlich macht, wenn du asynchrone Daten laden musst.

Implementierung:

import { useState, useEffect } from "react";

function useFetch<T>(url: string) {
  const [data, setData] = useState<T | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<Error | null>(null);

  useEffect(() => {
    const fetchData = async () => {
      setLoading(true);
      try {
        const response = await fetch(url);
        const result = await response.json();
        setData(result);
      } catch (err) {
        setError(err as Error);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [url]);

  return { data, loading, error };
}

export default useFetch;

Verwendung:

const { data, loading, error } = useFetch<User[]>('/api/users');

if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;

return <ul>{data?.map(user => <li key={user.id}>{user.name}</li>)}</ul>;

useDebounce: Performance optimieren

Die Handhabung häufiger Benutzereingaben, wie etwa bei der Suche oder der Formularausfüllung, erfordert oft ein Debouncing. Das bedeutet, dass Eingaben, die in schneller Folge erfolgen, nur nach einer gewissen Verzögerung verarbeitet werden, um die Anzahl der Funktionsaufrufe zu reduzieren und die Performance zu optimieren.

Ein useDebounce-Hook hilft dabei, diese häufigen Updates zu verlangsamen, indem er den Wert erst dann zurückgibt, wenn der Benutzer eine bestimmte Zeit lang keine Eingabe mehr gemacht hat. Dies ist besonders nützlich bei Eingabefeldern wie Suchleisten, um unnötige API-Anfragen oder teure Berechnungen zu vermeiden. Der useDebounce-Hook sorgt dafür, dass deine Anwendung nicht durch ständige Aktualisierungen überlastet wird und trägt so zur Verbesserung der Benutzererfahrung und Performance bei.

Implementierung:

import { useState, useEffect } from "react";

function useDebounce<T>(value: T, delay: number): T {
  const [debouncedValue, setDebouncedValue] = useState(value);

  useEffect(() => {
    const handler = setTimeout(() => setDebouncedValue(value), delay);

    return () => clearTimeout(handler);
  }, [value, delay]);

  return debouncedValue;
}

export default useDebounce;

Verwendung:

const [searchTerm, setSearchTerm] = useState('');
const debouncedSearch = useDebounce(searchTerm, 500);

useEffect(() => {
  if (debouncedSearch) {
    // Trigger API or other actions
  }
}, [debouncedSearch]);

useToggle: Boolesche Zustände einfach verwalten

Das Verwalten von Umschaltzuständen ist eine häufige Aufgabe in React-Anwendungen, besonders bei Modalen, Dropdown-Menüs oder Theme-Umschaltern. Der useToggle-Hook erleichtert diese Aufgabe, indem er eine einfache Möglichkeit bietet, zwischen zwei Zuständen zu wechseln – zum Beispiel zwischen „offen“ und „geschlossen“ oder „hell“ und „dunkel“.

Dieser Hook reduziert die Notwendigkeit, manuell mit useState und bedingten Anweisungen zu arbeiten, um den Zustand zu toggeln. Stattdessen kannst du useToggle verwenden, um effizient zwischen zwei Zuständen umzuschalten, was deinen Code klarer und kürzer macht. Es ist besonders nützlich, wenn du ein Element wie ein Menü oder ein Modal anzeigst oder verbirgst, ohne dabei unnötige Logik zu wiederholen.

Implementierung:

import { useState } from "react";

function useToggle(initialState = false) {
  const [state, setState] = useState(initialState);

  const toggle = () => setState(prev => !prev);

  return [state, toggle] as const;
}

export default useToggle;

Verwendung:

const [isModalOpen, toggleModal] = useToggle();

return (
  <div>
    <button onClick={toggleModal}>Toggle Modal</button>
    {isModalOpen && <p>Modal Content</p>}
  </div>
);

useLocalStorage: Daten lokal speichern

Das Speichern und Abrufen von Daten aus dem localStorage kann mit einem benutzerdefinierten Hook vereinfacht werden. Der useLocalStorage-Hook ermöglicht es, Daten auf dem Client-Seite dauerhaft zu speichern, sodass sie auch nach einem Seiten-Neuladen oder einer neuen Sitzung erhalten bleiben. Dies ist besonders nützlich für die Speicherung von Benutzereinstellungen, Präferenzen oder anderen persistierenden Informationen, die nicht in einer Datenbank oder auf einem Server gespeichert werden müssen.

Mit diesem Hook kannst du die Logik für das Abrufen und Speichern von Daten im localStorage zentralisieren, was den Code in deinen Komponenten vereinfacht und redundante Wiederholungen vermeidet. Zudem stellt der Hook sicher, dass der gespeicherte Zustand immer mit der React-Komponente synchronisiert wird, wodurch der Entwicklungsaufwand reduziert und die Performance verbessert wird.

Implementierung:

import { useState } from "react";

function useLocalStorage<T>(key: string, initialValue: T) {
  const [storedValue, setStoredValue] = useState<T>(() => {
    try {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      console.error(error);
      return initialValue;
    }
  });

  const setValue = (value: T) => {
    try {
      setStoredValue(value);
      window.localStorage.setItem(key, JSON.stringify(value));
    } catch (error) {
      console.error(error);
    }
  };

  return [storedValue, setValue] as const;
}

export default useLocalStorage;

Verwendung:

const [theme, setTheme] = useLocalStorage('theme', 'light');

return (
  <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
    Toggle Theme
  </button>
);

usePrevious: Den vorherigen Zustand verfolgen

Das Verfolgen des vorherigen Zustands eines Wertes kann in React-Anwendungen von unschätzbarem Wert sein, insbesondere bei Vergleichen, Animationen oder bei der Durchführung von Berechnungen, die auf dem vorherigen Zustand basieren. Der usePrevious-Hook ermöglicht es dir, den vorherigen Zustand einer Variable zu speichern und darauf zuzugreifen, was bei vielen Anwendungsfällen hilfreich sein kann, etwa bei der Implementierung von Übergängen oder beim Vergleichen von Zustandsänderungen.

Indem du diesen Hook verwendest, kannst du sicherstellen, dass du immer sowohl den aktuellen als auch den vorherigen Wert eines Zustands hast, ohne dafür zusätzliche Variablen oder komplexe Logik einführen zu müssen. Dies führt zu saubererem und effizienterem Code und hilft dir, bei Bedarf auf vergangene Zustände zuzugreifen.

Implementierung:

import { useEffect, useRef } from "react";

function usePrevious<T>(value: T): T | undefined {
  const ref = useRef<T>();

  useEffect(() => {
    ref.current = value;
  }, [value]);

  return ref.current;
}

export default usePrevious;

Verwendung:

const [count, setCount] = useState(0);
const prevCount = usePrevious(count);

return (
  <p>
    Now: {count}, Before: {prevCount}
  </p>
);

useClickOutside: Klicken außerhalb erkennen

Der useClickOutside-Hook ist besonders nützlich, um auf Klicks außerhalb eines bestimmten Elements zu reagieren. Dies ist oft erforderlich, wenn du modale Fenster, Dropdown-Menüs oder andere interaktive UI-Elemente schließen möchtest, sobald der Benutzer außerhalb des entsprechenden Bereichs klickt. Durch den Einsatz dieses Hooks kannst du sicherstellen, dass Benutzeroberflächen flexibel und benutzerfreundlich bleiben, indem sie automatisch geschlossen werden, wenn der Benutzer außerhalb des Fensters klickt.

Der Hook überwacht Klickereignisse und prüft, ob der Klick außerhalb des überwachten Elements erfolgt ist. Falls dies zutrifft, wird eine definierte Funktion ausgeführt, z. B. das Schließen eines Modals oder eines Dropdown-Menüs. So wird die Notwendigkeit vermieden, manuell mit Event-Listenern und komplexen Bedingungen zu arbeiten.

Implementierung:

import { useEffect, useRef } from "react";

function useClickOutside(handler: () => void) {
  const ref = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const handleClickOutside = (event: MouseEvent) => {
      if (ref.current && !ref.current.contains(event.target as Node)) {
        handler();
      }
    };

    document.addEventListener('mousedown', handleClickOutside);
    return () => document.removeEventListener('mousedown', handleClickOutside);
  }, [handler]);

  return ref;
}

export default useClickOutside;

Verwendung:

const ref = useClickOutside(() => setDropdownOpen(false));

return (
  <div ref={ref}>
    {dropdownOpen && <p>Dropdown Content</p>}
  </div>
);

useMediaQuery: Responsives Design verwalten

Das Verwalten von Media Queries in React kann durch den Einsatz des useMediaQuery-Hooks erheblich vereinfacht werden. In modernen Webanwendungen ist es wichtig, das Layout und das Design je nach Bildschirmgröße oder Gerätetyp anzupassen. Mit diesem Hook kannst du Media Queries direkt in deinen React-Komponenten verwenden, um das Design basierend auf der Bildschirmgröße oder anderen Eigenschaften des Viewports dynamisch anzupassen.

Der useMediaQuery-Hook gibt dir die Möglichkeit, auf verschiedene Bildschirmgrößen zu reagieren, ohne manuell JavaScript-basierte Media Queries oder CSS-Klassen zu verwalten. So kannst du in deiner Anwendung ganz einfach zwischen verschiedenen Layouts wechseln, je nachdem, ob der Benutzer auf einem Desktop, Tablet oder Smartphone arbeitet. Dieser Hook fördert eine saubere und reaktive Gestaltung von responsiven Anwendungen, die sich problemlos an verschiedene Geräte und Bildschirmgrößen anpassen.

Implementierung:

import { useState, useEffect } from "react";

function useMediaQuery(query: string): boolean {
  const [matches, setMatches] = useState(false);

  useEffect(() => {
    const mediaQueryList = window.matchMedia(query);

    const updateMatch = () => setMatches(mediaQueryList.matches);
    updateMatch();

    mediaQueryList.addEventListener('change', updateMatch);
    return () => mediaQueryList.removeEventListener('change', updateMatch);
  }, [query]);

  return matches;
}

export default useMediaQuery;

Verwendung:

const isMobile = useMediaQuery('(max-width: 768px)');

return <p>{isMobile ? 'Mobile View' : 'Desktop View'}</p>;

React Custom Hooks sind ein Beweis für die Flexibilität und Leistungsfähigkeit

Durch die Nutzung dieser React Custom Hooks können Entwickler komplexe Funktionalitäten vereinfachen und wieder verwendbaren, effizienten Code erstellen. Sie ermöglichen eine klare Trennung von Logik und UI, was zu besser wartbarem und skalierbarem Code führt. Die oben genannten Beispiele zeigen, wie benutzerdefinierte Hooks häufig auftretende Herausforderungen auf elegante Weise lösen, indem sie repetitive Aufgaben abstrahieren und die Codequalität verbessern. Indem Entwickler Logik in separate, wieder verwendbare Einheiten auslagern, können sie die Lesbarkeit ihrer Anwendung steigern und gleichzeitig die Komplexität reduzieren.

Diese Flexibilität ist besonders wertvoll, da sie es ermöglicht, Lösungen für verschiedene Anwendungsfälle zu schaffen, ohne dass redundanter Code geschrieben werden muss. Dadurch fördern benutzerdefinierte Hooks das DRY-Prinzip (Don’t Repeat Yourself) und tragen zu einer besseren Strukturierung der Anwendung bei.

Weitere Themen: Python Programmierung: Wie man einfach besseren Code schreibt

Newsletter Anmeldung

Bleiben Sie informiert! Wir informieren Sie über alle neuen Beiträge (max. 1 Mail pro Woche – versprochen)