Verständnis der Verwendung von Reducern in Redux

Avatar of Kingsley Silas
Kingsley Silas am

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

Ein Reducer ist eine Funktion, die Änderungen am Zustand einer Anwendung bestimmt. Sie verwendet die empfangene Aktion, um diese Änderung zu bestimmen. Wir haben Tools wie Redux, die uns helfen, Zustandsänderungen einer Anwendung in einem einzigen Store zu verwalten, damit sie konsistent ablaufen.

Warum erwähnen wir Redux, wenn wir über Reducer sprechen? Redux stützt sich stark auf Reducer-Funktionen, die den vorherigen Zustand und eine Aktion aufnehmen, um den nächsten Zustand auszuführen.

Wir werden uns in diesem Beitrag ausschließlich auf Reducer konzentrieren. Unser Ziel ist es, uns mit der Reducer-Funktion vertraut zu machen, damit wir sehen können, wie sie zur Aktualisierung des Zustands einer Anwendung verwendet wird – und letztendlich die Rolle verstehen, die sie in einem Zustandsmanager wie Redux spielen.

Was wir unter „Zustand“ verstehen

Zustandsänderungen basieren auf der Interaktion eines Benutzers oder sogar auf etwas wie einer Netzwerkanfrage. Wenn der Zustand der Anwendung von Redux verwaltet wird, geschehen die Änderungen innerhalb einer Reducer-Funktion – dies ist der einzige Ort, an dem Zustandsänderungen stattfinden. Die Reducer-Funktion nutzt den Anfangszustand der Anwendung und etwas namens Aktion, um zu bestimmen, wie der neue Zustand aussehen wird.

Wenn wir in Matheklasse wären, könnten wir sagen

initial state + action = new state

In Bezug auf eine tatsächliche Reducer-Funktion sieht das so aus

const contactReducer = (state = initialState, action) => {
  // Do something
}

Woher bekommen wir diesen Anfangszustand und die Aktion? Das sind Dinge, die wir definieren.

Der State-Parameter

Der state-Parameter, der an die Reducer-Funktion übergeben wird, muss der aktuelle Zustand der Anwendung sein. In diesem Fall nennen wir ihn unseren initialState, da er der erste (und aktuelle) Zustand sein wird und nichts ihm vorausgeht.

contactReducer(initialState, action)

Nehmen wir an, der Anfangszustand unserer App ist eine leere Kontaktliste und unsere Aktion ist das Hinzufügen eines neuen Kontakts zur Liste.

const initialState = {
  contacts: []
}

Das erstellt unseren initialState, der dem state-Parameter entspricht, den wir für die Reducer-Funktion benötigen.

Der Action-Parameter

Eine action ist ein Objekt, das zwei Schlüssel und ihre Werte enthält. Die Zustandsaktualisierung, die im Reducer stattfindet, hängt immer vom Wert von action.type ab. In diesem Szenario demonstrieren wir, was passiert, wenn der Benutzer versucht, einen neuen Kontakt zu erstellen. Definieren wir also action.type als NEW_CONTACT.

const action = {
  type: 'NEW_CONTACT',
  name: 'John Doe',
  location: 'Lagos Nigeria',
  email: '[email protected]'
}

Normalerweise gibt es einen payload-Wert, der das enthält, was der Benutzer sendet und zur Aktualisierung des Zustands der Anwendung verwendet würde. Es ist wichtig zu beachten, dass action.type erforderlich ist, action.payload jedoch optional ist. Die Verwendung von payload bringt ein gewisses Maß an Struktur in das Aussehen des Aktions-Objekts.

Zustand aktualisieren

Der Zustand ist als immutable (unveränderlich) gedacht, was bedeutet, dass er nicht direkt geändert werden sollte. Um einen aktualisierten Zustand zu erstellen, können wir Object.assign verwenden oder den Spread-Operator nutzen.

Object.assign

const contactReducer = (state, action) => {
  switch (action.type) {
    case 'NEW_CONTACT':
    return Object.assign({}, state, {
      contacts: [
        ...state.contacts,
        action.payload
      ]
    })
    default:
      return state
  }
}

Im obigen Beispiel haben wir Object.assign() verwendet, um sicherzustellen, dass wir den Zustand nicht direkt ändern. Stattdessen ermöglicht es uns, ein neues Objekt zurückzugeben, das mit dem an ihn übergebenen Zustand und dem vom Benutzer gesendeten Payload gefüllt ist.

Um Object.assign() verwenden zu können, ist es wichtig, dass das erste Argument ein leeres Objekt ist. Wenn Sie den Zustand als erstes Argument übergeben, wird er mutiert, was wir vermeiden wollen, um die Dinge konsistent zu halten.

Der Spread-Operator

Die Alternative zu object.assign() ist die Verwendung des Spread-Operators, wie folgt

const contactReducer = (state, action) => {
  switch (action.type) {
    case 'NEW_CONTACT':
    return {
        ...state, contacts:
        [...state.contacts, action.payload]
    }
    default:
      return state
  }
}

Dies stellt sicher, dass der eingehende Zustand intakt bleibt, während wir das neue Element unten anhängen.

Arbeiten mit einer Switch-Anweisung

Zuvor haben wir festgestellt, dass die Aktualisierung vom Wert von action.type abhängt. Die Switch-Anweisung bestimmt bedingt die Art der Aktualisierung, mit der wir es zu tun haben, basierend auf dem Wert von action.type.

Das bedeutet, dass ein typischer Reducer so aussehen wird

const addContact = (state, action) => {
  switch (action.type) {
    case 'NEW_CONTACT':
    return {
        ...state, contacts:
        [...state.contacts, action.payload]
    }
    case 'UPDATE_CONTACT':
      return {
        // Handle contact update
      }
    case 'DELETE_CONTACT':
      return {
        // Handle contact delete
      }
    case 'EMPTY_CONTACT_LIST':
      return {
        // Handle contact list
      }
    default:
      return state
  }
}

Es ist wichtig, dass wir default zurückgeben, für den Fall, dass der Wert von action.type, der im Aktions-Objekt angegeben ist, nicht mit dem übereinstimmt, was wir im Reducer haben – sagen wir, wenn die Aktion aus irgendeinem unbekannten Grund so aussieht

const action = {
  type: 'UPDATE_USER_AGE',
  payload: {
    age: 19
  }
}

Da wir diese Art von Aktionstyp nicht haben, wollen wir stattdessen zurückgeben, was wir im Zustand haben (den aktuellen Zustand der Anwendung). Alles, was das bedeutet, ist, dass wir uns im Moment nicht sicher sind, was der Benutzer zu erreichen versucht.

Putting everything together

Hier ist ein einfaches Beispiel dafür, wie ich die Reducer-Funktion in React implementiert habe.

Sehen Sie den Pen
reducer example
von Kingsley Silas Chijioke (@kinsomicrote)
auf CodePen.

Sie können sehen, dass ich Redux nicht verwendet habe, aber dies ist sehr ähnlich zu der Art und Weise, wie Redux Reducer zur Speicherung und Aktualisierung von Zustandsänderungen verwendet. Die primäre Zustandsaktualisierung erfolgt in der Reducer-Funktion, und der zurückgegebene Wert setzt den aktualisierten Zustand der Anwendung.

Möchten Sie es ausprobieren? Sie können die Reducer-Funktion erweitern, damit der Benutzer das Alter eines Kontakts aktualisieren kann. Ich würde gerne sehen, was Sie im Kommentarbereich entwickeln!

Das Verständnis der Rolle, die Reducer in Redux spielen, sollte Ihnen ein besseres Verständnis dafür vermitteln, was im Hintergrund geschieht. Wenn Sie daran interessiert sind, mehr über die Verwendung von Reducern in Redux zu erfahren, lohnt es sich, die offizielle Dokumentation zu lesen.