Recompose zur Funktionsfreigabe zwischen React-Komponenten verwenden

Avatar of Kingsley Silas
Kingsley Silas am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Das Teilen von Funktionalität zwischen React-Komponenten ist ein ziemlich häufiger Bedarf. Das Konzept besteht darin, dass wir das Verhalten an einer Stelle festlegen und es dann auf verschiedene Komponenten erweitern können. Higher-Order Components sind eine Möglichkeit, dies zu tun. Dennoch gibt es einen anderen Weg mit einer Bibliothek namens Recompose.

GitHub-Repo

Was ist Recompose?

Die Dokumentation hilft uns, das zu beantworten.

Recompose ist ein React Utility Belt für Funktionskomponenten und Higher-Order Components. Stellen Sie es sich wie lodash für React vor.

Im Grunde ist es eine Bibliothek für React, die eine Reihe von Helfern enthält, die verschiedene Higher-Order Components zurückgeben – was gut ist, da es einige der mühsamen Arbeit bei der Definition gängiger React-Muster abnimmt und sie sofort zur Erweiterung auf andere Komponenten verfügbar macht.

Was genau kann es tun? Nun, gehen wir ein paar Beispiele gemeinsam durch.

Status zu funktionalen zustandslosen Komponenten hinzufügen

Wenn Sie es am Namen erraten konnten, hat eine funktionale *zustandslose* Komponente keinen Status. Sie akzeptiert lediglich Props und gibt UI an das Frontend zurück.

const Greeting = props =>
  <p>
    Hello, {props.name}!
  </p>

In Szenarien, in denen Sie den Status in Ihrer funktionalen zustandslosen Komponente nutzen möchten, müssen Sie diese in eine Klassenkomponente umwandeln. Hier ist Recompose praktisch.

Recompose bietet Ihnen den Helfer withState(), um Ihren funktionalen zustandslosen Komponenten Status hinzuzufügen. Er verwaltet einen einzelnen Statuswert. Sie können nicht mehr als einen Statuswert in withState() verwalten, wie Sie es in Ihrer Klassenkomponente tun würden. Sie übergeben eine Funktion zur Aktualisierung des Statuswertes und einen optionalen Standardstatuswert.

So ist withState() strukturiert.

withState(
  stateName: string, // the name we call our state
  stateUpdaterName: string, // the name of the function to call
  initialState: any | (props: Object) => any // optional default state to pass
): HigherOrderComponent

Ein Zähler ist ein gängiges Beispiel, das zur Demonstration eines Konzepts verwendet wird. So können wir einen super einfachen Zähler mit dem withState()-Helfer von Recompose erstellen.

const App = withState("count", "handleCounter", 0)(({ count, handleCounter }) => {
  return (
    <div>
      <p>{count}</p>
      <button onClick={() => handleCounter(n => n + 1)}>Increment</button>
      <button onClick={() => handleCounter(n => n - 1)}>Decrement</button>
    </div>
  );
});

Da der withState()-Helfer bereits für uns verfügbar ist, können wir ihn sofort aufrufen und ihm die benötigten Parameter übergeben. Wiederum sind das:

  • stateName: Der Name, unter dem wir unseren Status bezeichnen.
  • stateUpdaterName: Der Name der aufzurufenden Funktion.
  • initialState: Optionaler Standardstatus, der übergeben werden kann.

Diese Parameter werden dann in das UI-Markup integriert, das wir im Frontend rendern möchten.

Es gibt eine weitere Möglichkeit, wie wir unsere Zählerkomponente erstellen könnten, und es lohnt sich, sie anzusehen, um mehr Übung im Einsatz eines Recompose-Helpers zu bekommen.

Zuerst erstellen wir eine Higher-Order-Komponente mit withState() und den erforderlichen Parametern.

const enhanced = withState("counter", "handleCounter", 0);

Als Nächstes erstellen wir die Counter-Komponente, die mit den withState()-Parametern arbeitet.

const Counter = ({ counter, handleCounter }) => (
  <div>
    <h1>{counter}</h1>
    <button onClick={() => handleCounter(n => n + 1)}>Increment</button>
    <button onClick={() => handleCounter(n => n - 1)}>Decrement</button>
  </div>
);

Beachten Sie, dass der Name des Status und der Updater-Funktion als Props an die Counter-Komponente übergeben wird.

Schließlich erstellen wir unsere App-Komponente, indem wir die Counter-Komponente in die Higher-Order-Komponente einwickeln.

const App = enhanced(Counter);

Siehe den Pen Recompose withState von Kingsley Silas Chijioke (@kinsomicrote) auf CodePen.

Hier ist ein weiterer beliebter Ansatz.

const enhanced = withState("count", "handleCounter", 0);
const App = enhanced(({ count, handleCounter }) => {
  return (
    <div>
      <p>{count}</p>
      <button onClick={() => handleCounter(n => n + 1)}>Increment</button>
      <button onClick={() => handleCounter(n => n - 1)}>Decrement</button>
    </div>
  );
});

Siehe den Pen Recompose withState v2 von Kingsley Silas Chijioke (@kinsomicrote) auf CodePen.

Status mit withHandlers() verwalten

Recompose verfügt auch über den Helfer withHandlers(), mit dem Sie Status verwalten können, indem Sie Funktionen definieren, die zum Aktualisieren des Status einer Komponente verwendet werden. Und Sie können ihn direkt neben withState() verwenden!

Dies sind im Wesentlichen Higher-Order-Funktionen, die Props aufnehmen und eine Handler-Funktion zurückgeben. Lassen Sie uns die Struktur aufschlüsseln, wie wir es im vorherigen Beispiel getan haben.

withHandlers({
  incrementCounter: props => event => {
    event.preventDefault();
    props.handleCounter(props.count + 1);
  }
})

Zuerst haben wir incrementCounter identifiziert, das unserer Counter-Komponente zur Verfügung steht, um den Zählerstand bei einem Klick zu aktualisieren.

Als Nächstes konstruieren wir den Zähler wie zuvor – als Higher-Order-Komponente mit withState().

const enhancedState = withState("count", "handleCounter", 0);

Jetzt definieren wir unsere Funktionen und setzen withHandlers() ein.

const enhancedHandler = withHandlers({
  incrementCounter: props => event => {
    event.preventDefault();
    props.handleCounter(props.count + 1);
  },
  decrementCounter: props => event => {
    event.preventDefault();
    props.handleCounter(props.count - 1);
  }
});

Wir haben eine Higher-Order-Komponente namens enhancedHandler konstruiert und withState() verwendet, um zwei Funktion-Handler darin zu definieren: incrementCounter und decrementCounter. Diese Handler enthalten Parameter, die als Props an die aufrufenden Komponenten übergeben werden. Sie werden benötigt, wenn wir den Status der mit withState() definierten Komponente aktualisieren wollen.

Nun zur Erstellung unserer Zählerkomponente.

const Counter = ({ count, incrementCounter, decrementCounter }) => (
  <div>
    <h1>{count}</h1>
    <button onClick={incrementCounter}>Increment</button>
    <button onClick={decrementCounter}>Decrement</button>
  </div>
);

Sehen Sie das? Status und Handler werden als Props an die Zählerkomponente übergeben.

Um die von uns definierten Higher-Order-Komponenten zu nutzen, müssen wir die Counter-Komponente an enhancedHandler übergeben und diese als Parameter an enhancedState übergeben.

Mit anderen Worten

const App = enhancedState(enhancedHandler(Counter));

Siehe den Pen Recompose withState & withHandlers von Kingsley Silas Chijioke (@kinsomicrote) auf CodePen.

Mehrere Higher-Order-Komponenten zusammensetzen

Im letzten Beispiel haben wir zwei Higher-Order-Komponenten verwendet. Gibt es eine bessere Möglichkeit, sie miteinander zu verketten? Ganz sicher! Recompose stellt uns einen compose()-Helfer zur Verfügung, um genau das zu tun. Wir können compose() verwenden, um eine Komponente zu erstellen, die beide Higher-Order-Komponenten auf einmal zusammensetzt.

const enhanced = compose(
  withState("count", "handleCounter", 0),
  withHandlers({
    incrementCounter: props => event => {
      event.preventDefault();
      props.handleCounter(props.count + 1);
    },
    decrementCounter: props => event => {
      event.preventDefault();
      props.handleCounter(props.count - 1);
    }
  })
);

Jetzt können wir die erweiterte Komponente in unserer App-Komponente verwenden.

const App = enhanced(({ count, incrementCounter, decrementCounter }) => {
  return (
    <div>
      <p>{count}</p>
      <button onClick={incrementCounter}>Increment</button>
      <button onClick={decrementCounter}>Decrement</button>
    </div>
  );
});

Siehe den Pen Recompose – compose withState & withHandlers von Kingsley Silas Chijioke (@kinsomicrote) auf CodePen.

Status mit einem Redux-ähnlichen Reducer verwalten

Eine weitere nützliche Funktion von Recompose ist, dass es Ihnen ermöglicht, den Status mit einer Reducer-Funktion (withReducer) zu verwalten. Ein Reducer aktualisiert den Status einer Komponente als Reaktion auf eine bestimmte Aktion.

Die Struktur von withReducer() sieht so aus.

withReducer<S, A>(
  stateName: string,
  dispatchName: string,
  reducer: (state: S, action: A) => S,
  initialState: S | (ownerProps: Object) => S
): HigherOrderComponent</S>

Der erste Parameter ist der Name des Status. Der zweite ist die dispatch-Methode. dispatch wird zum Versenden von Aktionen verwendet, ähnlich wie wir es in Redux tun. Als Nächstes haben wir den reducer und den Anfangsstatus.

Im Kontext unserer Zählerkomponente wird withReducer() den Status des Zählers aktualisieren: Der Zähler wird mit einer Aktion, die wir als *increment* bezeichnen, erhöht und umgekehrt wird der Zähler mit einer Aktion, die wir als *decrement* bezeichnen, verringert.

Zuerst erstellen wir eine erweiterte Komponente, indem wir withReducer und withHandlers zusammensetzen.

const enhanced = compose(
  withReducer(
    "count",
    "dispatch",
    (state, action) => {
      switch (action.type) {
        case "INCREMENT":
          return state + 1;
        case "DECREMENT":
          return state - 1;
        default:
          return state;
      }
    },
    0
  ),
  withHandlers({
    incrementCounter: ({ dispatch }) => e => dispatch({ type: "INCREMENT" }),
    decrementCounter: ({ dispatch }) => e => dispatch({ type: "DECREMENT" })
  })
);

incrementCounter und decrementCounter reagieren auf DOM-Ereignisse und versenden einen Aktionstyp. Der Status wird je nach Aktionstyp aktualisiert. Als Nächstes müssen wir dies in unserer Komponente nutzen.

const App = enhanced(({ count, incrementCounter, decrementCounter }) => {
  return (
    <div>
      <p>{count}</p>
      <button onClick={incrementCounter}>Increment</button>
      <button onClick={decrementCounter}>Decrement</button>
    </div>
  );
});

Siehe den Pen Recompose – reducer von Kingsley Silas Chijioke (@kinsomicrote) auf CodePen.

Ziemlich nett, oder?

Hoffentlich gibt Ihnen dies eine gute Vorstellung davon, was Recompose ist und wie die Fülle von Helfern der Bibliothek die React-Entwicklung rationalisieren kann, insbesondere wenn es um die Verwaltung und den Aufruf von Zuständen geht.

Natürlich gibt es bei Recompose viel mehr als das, was wir hier behandelt haben. Ein kurzer Blick auf die API-Dokumentation zeigt, dass es viele Higher-Order-Komponenten gibt, die Sie nutzen können, je nach den Anforderungen Ihrer Anwendung. Gehen Sie voran, bauen Sie und hinterlassen Sie gerne einen Kommentar, wenn Sie Fragen haben!