navigation Navigation


Einführung


React Custom Hooks sind eine elegante Lösung zur Extraktion und Wiederverwendung von Komponentenlogik. Seit React 16.8 ermöglichen sie Entwicklern, stateful Logik zwischen Komponenten zu teilen, ohne die Komponentenhierarchie zu verändern. Custom Hooks folgen der Namenskonvention “use” und können auf die eingebauten React Hooks zugreifen. Dadurch wird komplexer, sich wiederholender Code in übersichtliche, eigenständige Funktionen gekapselt. Dies verbessert nicht nur die Lesbarkeit und Wartbarkeit des Codes, sondern fördert auch die Modularität und ermöglicht die Zusammenstellung komplexer Funktionalitäten aus kleineren, wiederverwendbaren Einheiten.

Inhaltsverzeichnis

    Einführung

    Custom Hooks sind JavaScript-Funktionen, die es ermöglichen, zustandbehaftete Logik zwischen verschiedenen React-Komponenten wiederzuverwenden.

    Man kann sich Custom Hooks wie kleine, spezialisierte Werkzeuge in einer großen Werkzeugkiste vorstellen. Anstatt immer wieder denselben Code in verschiedenen Components zu schreiben, erstellt man ein Werkzeug (Hook), das man überall verwenden kann, wo man es benötigt.

    Wichtige Regeln

    • Der Name beginnt mit use (Namenskonvention)
    • Custom Hooks können andere Hooks aufrufen
    • Geben kein JSX/TSX zurück, daher die Endung ist .js/.ts

    Vorteile von Custom Hooks

    Custom Hooks können mehrere Probleme lösen.

    • Wiederverwendbarkeit: Dieselbe Logik kann in mehreren Komponenten verwendet werden.
    • Trennung von Concerns: UI-Logik wird von Business-Logik getrennt.
    • Testbarkeit: Isolierte Logik ist einfacher zu testen.
    • Lesbarkeit: Komponenten werden übersichtlicher und fokussierter.

    Einfaches Beispiel

    In diesem Beispiel werden wir einen Hook definieren, bei dem wir einen benutzerdefinierten Zähler mit einem Set an Funktionen definieren.

    Wie wir bereits erfahren haben, sind Custom Hooks einfache JavaScript- oder TypeScript-Funktionen.

    Wir erstellen unseren Custom Hook, welches Funktionen rund um einen Counter bereitstellt.

    useCustomCounter.js
    import { useState } from 'react';
    
    function useCustomCounter(initialValue) {
    
        const [counter, setCounter] = useState(initialValue);
    
        const incrementCounter = () => {
            setCounter(prevCounter => prevCounter + 1);
        };
        
        const decrementCounter = () => {
            setCounter(prevCounter => prevCounter - 1);
        };
        
        const resetCounter = () => {
            setCounter(initValue);
        };
    
        return [
            counter,
            incrementCounter,
            decrementCounter,
            resetCounter
        ];
    
    }
    
    export default useCustomCounter;

    Damit haben wir unseren Custom Hook definiert. Wenn wir uns den Rückgabewert dieser Funktion anschauen, werden wir eine bestimmte Ähnlichkeit mit, beispielsweise, useState feststellen. Hier allerdings, bestimmen wir, wie unser Rückgabewert aussieht.

    Nun verwenden wir unseren Custom Hook.

    App.jsx
    import useCustomCounter from './useCustomCounter';
    
    function App() {
    
        const [
            counter,
            incrementCounter,
            decrementCounter,
            resetCounter
        ] = useCustomCounter(0);
    
        return (
            <>
                <h3>Zähler: {counter}</h3>
                <hr />
                <div style={{
                    display: 'flex',
                    alignItems: 'center',
                    gap: 10
                }}>
                    <button onClick={incrementCounter}>
                        Zähler erhöhen
                    </button>
                    <button onClick={decrementCounter}>
                        Zähler reduzieren
                    </button>
                    <button onClick={resetCounter}>
                        Zähler zurücksetzen
                    </button>
                </div>
            </>
        );
    
    }
    
    export default App;

    Als Ergebnis haben wir ein Component, in dem wir unseren Custom Hook verwenden. Diesen Custom Hook können wir mehrmals an unterschiedlichen Stellen verwenden.

    React Custom Hook - Beispiel 1


    Was wir ebenfalls direkt in diesem Beispiel tun können, ist es unseren Custom Hook mit einem anderen Startwert verwenden. Lasst uns hierzu unser Beispiel erweitern. Dabei erweitern wir lediglich unser App Component. Die Logik unseres Custom Hooks bleibt natürlich gleich.

    App.jsx
    import useCustomCounter from './useCustomCounter';
    
    function App() {
    
        const [
            counter,
            incrementCounter,
            decrementCounter,
            resetCounter
        ] = useCustomCounter(0);
    
        const [
            counterTwo,
            incrementCounterTwo,
            decrementCounterTwo,
            resetCounterTwo
        ] = useCustomCounter(12);
    
        return (
            <>
                <h3>Zähler: {counter}</h3>
                <hr />
                <div style={{
                    display: 'flex',
                    alignItems: 'center',
                    gap: 10
                }}>
                    <button onClick={incrementCounter}>
                        Zähler erhöhen
                    </button>
                    <button onClick={decrementCounter}>
                        Zähler reduzieren
                    </button>
                    <button onClick={resetCounter}>
                        Zähler zurücksetzen
                    </button>
                </div>
                <hr />
                <h3>Zähler (2): {counterTwo}</h3>
                <hr />
                <div style={{
                    display: 'flex',
                    alignItems: 'center',
                    gap: 10
                }}>
                    <button onClick={incrementCounterTwo}>
                        Zähler erhöhen
                    </button>
                    <button onClick={decrementCounterTwo}>
                        Zähler reduzieren
                    </button>
                    <button onClick={resetCounterTwo}>
                        Zähler zurücksetzen
                    </button>
                </div>
            </>
        );
    
    }
    
    export default App;

    Wenn wir nun unsere Applikation im Browser neuladen, stellen wir fest, dass wir zwei unterschiedliche Startwerte bei unseren Zählern haben.

    • Zähler 1: Startwert = 0
    • Zähler 2: Startwert = 12

    React Custom Hook - Beispiel 1 erweitert


    Wir können unseren Custom Hook useCustomCounter noch weiter erweitern. Wir können nämlich mehrere Argumente übergeben, um entsprechend die Konfigurationsmöglichkeit zu erweitern.

    Bis jetzt war die Schrittweite bei unserem Zähler immer 1. Lasst uns unseren Custom Hook so erweitern, dass wir die Schrittweite für jede Verwendung anders definieren können. Sollten wir dabei keine eigene Schrittweite übergeben, werden wir weiterhin 1, als Standardwert, verwenden.

    Diesmal müssen wir sowohl unsere useCustomCounter.js, als auch unsere App.jsx anpassen. Fangen wir mit dem Custom Hook an.

    useCustomCounter.js
    import { useState } from 'react';
    
    function useCustomCounter(initialValue, counterStep = 1) {
    
        const [counter, setCounter] = useState(initialValue);
    
        const incrementCounter = () => {
            setCounter(prevCounter => prevCounter + counterStep);
        };
        
        const decrementCounter = () => {
            setCounter(prevCounter => prevCounter - counterStep);
        };
        
        const resetCounter = () => {
            setCounter(initValue);
        };
    
        return [
            counter,
            incrementCounter,
            decrementCounter,
            resetCounter
        ];
    
    }
    
    export default useCustomCounter;

    Hiermit haben wir counterStep Parameter eingeführt und diesen auf den Standardwert von “1” gesetzt. Statt der fixen “1”, verwenden wir nun in unseren Funktionen die Parameter-Variable counterStep.

    Wenn wir an dieser Stelle alles so belassen, wird unsere Anwendung genauso funktionieren wie bisher.

    Um aber die Funktionalität zu testen, passen wir auch unsere App.jsx an und übergeben bei den beiden Verwendungen von useCustomCounter nicht nur unterschiedliche Startwerte, sondern auch unterschiedliche Schrittweiten.

    App.jsx
    import useCustomCounter from './useCustomCounter';
    
    function App() {
    
        const [
            counter,
            incrementCounter,
            decrementCounter,
            resetCounter
        ] = useCustomCounter(0, 2);
    
        const [
            counterTwo,
            incrementCounterTwo,
            decrementCounterTwo,
            resetCounterTwo
        ] = useCustomCounter(12, 6);
    
        return (
            <>
                <h3>Zähler: {counter}</h3>
                <hr />
                <div style={{
                    display: 'flex',
                    alignItems: 'center',
                    gap: 10
                }}>
                    <button onClick={incrementCounter}>
                        Zähler erhöhen
                    </button>
                    <button onClick={decrementCounter}>
                        Zähler reduzieren
                    </button>
                    <button onClick={resetCounter}>
                        Zähler zurücksetzen
                    </button>
                </div>
                <hr />
                <h3>Zähler (2): {counterTwo}</h3>
                <hr />
                <div style={{
                    display: 'flex',
                    alignItems: 'center',
                    gap: 10
                }}>
                    <button onClick={incrementCounterTwo}>
                        Zähler erhöhen
                    </button>
                    <button onClick={decrementCounterTwo}>
                        Zähler reduzieren
                    </button>
                    <button onClick={resetCounterTwo}>
                        Zähler zurücksetzen
                    </button>
                </div>
            </>
        );
    
    }
    
    export default App;

    Für unsere erste Verwendung übergeben wir die Schrittweite von “2”.

    const [
        counter,
        incrementCounter,
        decrementCounter,
        resetCounter
    ] = useCustomCounter(0, 2);

    Und für unsere zweite Verwendung übergeben wir eine Schrittweite von “6”.

    const [
        counterTwo,
        incrementCounterTwo,
        decrementCounterTwo,
        resetCounterTwo
    ] = useCustomCounter(0, 6);

    Als Ergebnis haben wir weiterhin die gleiche Anwendung, bei der sich die Änderung von Zählern unterschiedlich verhält.

    React Custom Hook - Beispiel 1 - weiterer Parameter