5 Best Practices für die Verwendung von React Hooks in der Produktion

Der Autor des Artikels, die Übersetzung , von denen wir heute veröffentlicht werden, so dass commerce angenommen React Haken am Anfang 2019 - zum Zeitpunkt ihres Erscheinens in 16.8.0 React. Seitdem verarbeiten die Programmierer des Unternehmens ihren Code ständig und übersetzen ihn in Hooks. Mit React-Hooks können Sie den Komponentenstatus und andere React-Funktionen verwenden, ohne Klassen zu verwenden. Mithilfe von Hooks können Sie bei der Arbeit mit Funktionskomponenten eine Verbindung zu den Ereignissen des Komponentenlebenszyklus herstellen und auf Änderungen ihres Status reagieren.



Kurz über die Ergebnisse der Implementierung von Hooks


Wenn wir kurz und bündig darüber sprechen, was uns die Hooks gegeben haben, stellt sich heraus, dass sie zur Vereinfachung der Codebasis beigetragen haben, indem sie die Logik aus den Komponenten extrahiert und die Zusammensetzung verschiedener Funktionen erleichtert haben. Darüber hinaus hat die Verwendung von Haken dazu geführt, dass wir viel gelernt haben. Zum Beispiel, wie Sie Ihren Code durch kontinuierliche Verbesserung der vorhandenen Funktionalität besser strukturieren können. Wir sind sicher, dass wir noch viel mehr interessante Dinge lernen werden, während wir weiter mit React Hooks arbeiten.

Stärken der Hook-Implementierung


Die Einführung von Haken hat uns Folgendes gegeben:

  • Verbesserung der Lesbarkeit von Code. Dies ist möglich durch die Verwendung kleinerer Komponentenbäume als zuvor. Die Erstellung solcher Komponentenbäume wird durch unseren Wunsch erleichtert, Rendering-Eigenschaften und Komponenten höherer Ordnung aufzugeben.
  • Verbesserung der Code-Debugging-Funktionen. Wir verfügten über eine verbesserte visuelle Darstellung des Codes und zusätzliche Debugging-Informationen, die von den React-Entwicklertools bereitgestellt wurden.
  • Verbesserung der Modularität des Projekts. Aufgrund der Funktionsweise von Hooks wurde das Erstellen und Anwenden von Logik, die für die wiederholte Verwendung geeignet ist, vereinfacht.
  • Aufgabentrennung. Reaktionskomponenten sind für das Erscheinungsbild der Schnittstellenelemente verantwortlich, und Hooks bieten Zugriff auf die gekapselte Programmlogik.

Jetzt möchten wir unsere Empfehlungen zur Verwendung von Haken in der Produktion teilen.

1. Rufen Sie Hooks rechtzeitig von Komponenten ab und erstellen Sie benutzerdefinierte Hooks


Die Verwendung von Haken in Funktionskomponenten ist ziemlich einfach. Zum Beispiel haben wir uns schnell irgendwo beworben React.useState- React.useEffectund unsere Arbeit fortgesetzt. Dieser Ansatz erlaubt es jedoch nicht, alle Möglichkeiten, die Hooks bieten können, voll auszuschöpfen. Presenting React.useStatein Form eines kleinen use<StateName>State, und React.useEffect- in Form use<EffectName>Effectkonnten wir folgendes erreichen:

  1. Komponenten sind kleiner als bei normalen Haken.
  2. Haken können in verschiedenen Komponenten wiederverwendet werden.
  3. , React, , . , State<StateName> State. React.useState, .

Das Abrufen von Hooks trägt auch dazu bei, dass wiederverwendbare und gemeinsam genutzte Logik in verschiedenen Teilen der Anwendung besser sichtbar ist. Eine ähnliche oder doppelte Logik ist schwieriger zu erkennen, wenn Sie nur im Komponentencode integrierte Hooks verwenden. Die resultierenden Hooks können klein sein und sehr wenig Code enthalten useToggleState. Auf der anderen Seite können größere Haken useProductFetcherjetzt mehr Funktionen enthalten. Beides hat uns geholfen, die Codebasis zu vereinfachen, indem wir die Größe der React-Komponenten reduziert haben.

Im folgenden Beispiel wird ein kleiner React-Hook erstellt, mit dem die Auswahl der Elemente gesteuert werden kann. Die Vorteile der Kapselung dieser Funktionalität werden sofort deutlich, wenn Sie feststellen, wie oft eine solche Logik in der Anwendung verwendet wird. Zum Beispiel, um eine Reihe von Aufträgen aus einer Liste auszuwählen.

//  

function Component() {
    const [selected, setSelected] = React.useState()
    const select = React.useCallback(id => setSelected(/** ... */), [
        selected,
        setSelect
    ])

    return <List selectedIds={selected} onSelect={id => select(id)} />
}

//   

const useSelection = () => {
    const [selected, setSelected] = React.useState()
    const select = React.useCallback(id => setSelected(/** ... */), [
        selected,
        setSelect
    ])

    return [selected, select]
}

function Component() {
    const [selected, select] = useSelection()

    return <List selectedIds={selected} onSelect={id => select(id)} />
}

2. Über die Vorteile von React.useDebugValue


Der Standard-Hook React.useDebugValue bezieht sich auf die wenig bekannten React-Funktionen. Dieser Hook kann dem Entwickler beim Debuggen des Codes helfen. Er kann nützlich sein, um ihn in Hooks zu verwenden, die für die Freigabe vorgesehen sind. Dies sind Benutzer-Hooks, die in vielen Komponenten der Anwendung verwendet werden. Es wird jedoch useDebugValuenicht empfohlen, es in allen Benutzer-Hooks zu verwenden, da die integrierten Hooks bereits Standard-Debug-Werte protokollieren.

Stellen Sie sich vor, Sie erstellen einen benutzerdefinierten Hook, mit dem Sie entscheiden können, ob bestimmte Funktionen der Anwendung aktiviert werden müssen. Die der Entscheidung zugrunde liegenden Anwendungsstatusdaten können aus verschiedenen Quellen stammen. Sie können in einem React-Kontextobjekt gespeichert werden, über das der Zugriff organisiert ist React.useContext.

Um dem Entwickler beim Debuggen zu helfen, kann es bei der Arbeit mit React-Entwicklertools hilfreich sein, den analysierten Flag-Namen ( flagName) und die Variante des Flag-Werts ( flagVariation) zu kennen. In diesem Fall kann uns die Verwendung eines kleinen Hakens helfen React.useDebugValue:

export default function useFeatureToggle(flagName, flagVariation = true) {
    const flags = React.useContext(FlagsContext)
    const isFeatureEnabled = getIsFeatureEnabled(flagName, flagVariation)(flags)

    React.useDebugValue({
        flagName,
        flagVariation,
        isEnabled: isFeatureEnabled
    })

    return isFeatureEnabled
}

Wenn wir jetzt mit den Tools des React-Entwicklers arbeiten, können wir Informationen über die Option des Flag-Werts, über den Flag-Namen und darüber, ob die für uns interessante Funktion aktiviert ist oder nicht, anzeigen.


Arbeiten mit React-Entwicklertools nach dem Anwenden des React.useDebugValue-Hooks

Beachten Sie, dass in Fällen, in denen Benutzer-Hooks Standard-Hooks wieReact.useStateoder verwendenReact.useRef, solche Hooks bereits die entsprechenden Status- oder Ref-Objektdaten protokollieren. Infolgedessen ist die Verwendung von Ansichtskonstrukten hierReact.useDebugValue({ state })nicht besonders nützlich.

3. Die Kombination und Zusammensetzung der Haken


Als wir begannen, Hooks in unserer Arbeit zu implementieren und immer mehr Hooks in Komponenten zu verwenden, stellte sich schnell heraus, dass 5-10 Hooks in derselben Komponente vorhanden sein könnten. In diesem Fall wurden Haken verschiedener Typen verwendet. Zum Beispiel könnten wir 2-3 Hooks verwenden React.useState, dann einen Hook React.useContext(um beispielsweise Informationen über den aktiven Benutzer zu erhalten), einen Hook React.useEffectund auch Hooks aus anderen Bibliotheken wie React-Router oder React-Intl .

Das Obige wurde immer wieder wiederholt, so dass selbst sehr kleine Komponenten nicht so kompakt waren. Um dies zu vermeiden, haben wir begonnen, diese einzelnen Hooks in Benutzer-Hooks zu extrahieren, deren Gerät von der Komponente oder einer Anwendungsfähigkeit abhängt.

Stellen Sie sich einen Anwendungsmechanismus vor, mit dem eine Bestellung erstellt werden soll. Bei der Entwicklung dieses Mechanismus wurden viele Komponenten sowie Haken verschiedener Typen verwendet. Diese Haken können als benutzerdefinierte Haken kombiniert werden, wodurch die Benutzerfreundlichkeit der Komponenten erhöht wird. Hier ist ein Beispiel für das Kombinieren eines Satzes kleiner Haken in einem Haken.

function OrderCreate() {
    const {
        orderCreater,
        orderFetcher,
        applicationContext,
        goToNextStep,
        pendingOrder,
        updatePendingChanges,
        revertPendingChanges
    } = useOrderCreate()

    return (/** ...children */)
}

4. Vergleich von React.useReducer und React.useState


Wir haben oft auf React.useStateeinen Standardhaken zurückgegriffen, um mit dem Zustand der Komponenten zu arbeiten. Im Laufe der Zeit muss der Zustand der Komponente jedoch möglicherweise kompliziert sein, was von den neuen Anforderungen an die Komponente abhängt, beispielsweise vom Vorhandensein mehrerer Werte im Zustand. In bestimmten Fällen kann die Verwendung React.useReducerdazu beitragen, die Verwendung mehrerer Werte zu vermeiden und die Logik der Aktualisierung des Status zu vereinfachen. Stellen Sie sich die Statusverwaltung vor, wenn Sie HTTP-Anforderungen stellen und Antworten empfangen. Um dies zu tun, müssen Sie möglicherweise mit Werten arbeiten, wie isLoading, dataunderror. Stattdessen kann der Zustand mithilfe eines Reduzierers gesteuert werden, der über verschiedene Aktionen zur Verwaltung von Zustandsänderungen verfügt. Dieser Ansatz ermutigt den Entwickler im Idealfall, den Zustand der Schnittstelle in Form einer Zustandsmaschine wahrzunehmen.

Der übertragene React.useReducerReduzierer ähnelt den in Redux verwendeten Reduzierern, bei denen das System den aktuellen Status der Aktion empfängt und den nächsten Status zurückgeben sollte. Die Aktion enthält Informationen zu ihrem Typ sowie Daten, auf deren Grundlage der nächste Zustand gebildet wird. Hier ist ein Beispiel eines einfachen Reduzierers zur Steuerung eines bestimmten Zählers:

const initialState = 0;
const reducer = (state, action) => {
    switch (action) {
        case 'increment': return state + 1;
        case 'decrement': return state - 1;
        case 'reset': return 0;
        default: throw new Error('Unexpected action');
    }
};

Dieser Reduzierer kann isoliert getestet und dann in der Komponente verwendet werden, indem React.useReducer:

function Component() {
    const [count, dispatch] = React.useReducer(reducer, initialState);

    return (
        <div>
            {count}
            <button onClick={() => dispatch('increment')}>+1</button>
            <button onClick={() => dispatch('decrement')}>-1</button>
            <button onClick={() => dispatch('reset')}>reset</button>
        </div>
    );
};

Hier können wir das anwenden, was wir in den vorherigen drei Abschnitten untersucht haben, nämlich alles in extrahieren useCounterReducer. Dadurch wird der Code verbessert, indem Informationen zum Aktionstyp vor einer Komponente ausgeblendet werden, die das Erscheinungsbild eines Schnittstellenelements beschreibt. Auf diese Weise wird verhindert, dass Implementierungsdetails in die Komponente gelangen, und wir haben zusätzliche Möglichkeiten zum Debuggen von Code. So sehen der resultierende benutzerdefinierte Hook und die Komponente, die ihn verwendet, aus:

const CounterActionTypes = {
    Increment: 'increment',
    Decrement: 'decrement',
    Reset: 'reset',
}

const useCounterReducer = (initialState) => {
    const [count, dispatch] = React.useReducer(reducer, initialState);

    const increment = React.useCallback(() => dispatch(CounterActionTypes.Increment));
    const decrement = React.useCallback(() => dispatch(CounterActionTypes.Decrement));
    const reset = React.useCallback(() => dispatch(CounterActionTypes.Reset));

    return {
        count,
        increment,
        decrement
    }
}

function Component() {
    const {count, increment} = useCounterReducer(0);

    return (
        <div>
            {count}
            <button onClick={increment}>+1</button>
        </div>
    );
};

5. Allmähliche Implementierung von Haken


Auf den ersten Blick mag die Idee, schrittweise Haken einzuführen, nicht ganz logisch erscheinen, aber hier schlage ich vor, dass diejenigen, die so denken, einfach meiner Argumentation folgen. Im Laufe der Zeit finden verschiedene Muster Anwendung in der Codebasis. In unserem Fall umfassen diese Muster Komponenten höherer Ordnung, Rendering-Eigenschaften und jetzt Hooks. Bei der Übersetzung eines Projekts in ein neues Muster versuchen Entwickler nicht, den gesamten Code sofort neu zu schreiben, was im Allgemeinen fast unmöglich ist. Daher müssen Sie einen Plan für die Übertragung des Projekts an React-Hooks entwickeln, der keine wesentlichen Änderungen am Code vorsieht. Diese Aufgabe kann sehr schwierig sein, da Änderungen am Code normalerweise zu einer Zunahme seiner Größe und Komplexität führen. Durch die Einführung von Haken versuchen wir dies zu vermeiden.

Unsere Codebasis verwendet klassenbasierte Komponenten und Funktionskomponenten. Unabhängig davon, welche Komponente in einer bestimmten Situation verwendet wurde, haben wir versucht, die Logik über React-Hooks zu teilen. Zuerst implementieren wir die Logik in Hooks (oder wiederholen die vorhandene Implementierung bestimmter Mechanismen in ihnen) und erstellen dann kleine Komponenten höherer Ordnung, in denen diese Hooks verwendet werden. Danach werden diese Komponenten höherer Ordnung verwendet, um klassenbasierte Komponenten zu erstellen. Infolgedessen verfügen wir über eine Logik an einem Ort, die in Komponenten verschiedener Art verwendet werden kann. Hier ist ein Beispiel für die Implementierung der Hook-Funktionalität in Komponenten durch Komponenten höherer Ordnung.

export const injectTracking = (propName = 'tracking') => WrappedComponent => {
    const WithTracking = props => {
        const tracking = useTracking();

        const trackingProp = {
            [propName]: tracking,
        };

        return <WrappedComponent {...props} {...trackingProp} />;
    };

    WithTracking.displayName = wrapDisplayName(WrappedComponent, 'withTracking');

    return WithTracking;
};

export default injectTracking;

Dies zeigt die Implementierung der Hook-Funktionalität useTrackingin einer Komponente WrappedComponent. Dies ermöglichte es uns übrigens unter anderem, die Aufgaben der Implementierung von Hooks und des Umschreibens von Tests in den alten Teilen des Systems zu trennen. Mit diesem Ansatz verfügen wir weiterhin über Mechanismen zur Verwendung von Hooks in allen Teilen der Codebasis.

Zusammenfassung


Hier sind einige Beispiele, wie die Verwendung von React-Hooks unsere Codebasis verbessert hat. Wir hoffen, dass Hooks auch Ihrem Projekt zugute kommen können.

Liebe Leser! Verwenden Sie React Hooks?


All Articles