() translation by (you can also view the original English article)
Wenn Sie React lernen, werden Sie fast immer Leute sagen hören, wie großartig Redux ist und dass Sie es versuchen sollten. Das React-Ökosystem wächst rasant und es gibt so viele Bibliotheken, dass Sie sich mit React verbinden können, z. B. flow, redux, middleware, mobx usw.
React zu lernen ist einfach, aber es braucht Zeit, sich an das gesamte React-Ökosystem zu gewöhnen. Dieses Tutorial ist eine Einführung in einen der integralen Bestandteile des React-Ökosystems - Redux.
Grundlegende Nicht-Redux-Terminologie
Hier sind einige der häufig verwendeten Terminologien, mit denen Sie möglicherweise nicht vertraut sind, die jedoch nicht spezifisch für Redux an sich sind. Sie können diesen Abschnitt durchblättern und hierher zurückkehren, wenn/etwas keinen Sinn ergibt.
Reine Funktion
Eine reine Funktion ist nur eine normale Funktion mit zwei zusätzlichen Einschränkungen, die sie erfüllen muss:
- Bei einer Reihe von Eingaben sollte die Funktion immer dieselbe Ausgabe zurückgeben.
- Es entstehen keine Nebenwirkungen.
Hier ist zum Beispiel eine reine Funktion, die die Summe zweier Zahlen zurückgibt.
1 |
/* Pure add function */
|
2 |
const add = (x,y) => { |
3 |
return x+y; |
4 |
}
|
5 |
|
6 |
console.log(add(2,3)) //5 |
7 |
Reine Funktionen liefern eine vorhersehbare Ausgabe und sind deterministisch. Eine Funktion wird unrein, wenn sie etwas anderes als die Berechnung ihres Rückgabewerts ausführt.
Die folgende Add-Funktion verwendet beispielsweise einen globalen Status, um die Ausgabe zu berechnen. Darüber hinaus protokolliert die Funktion den Wert in der Konsole, was als Nebeneffekt angesehen wird.
1 |
const y = 10; |
2 |
|
3 |
const impureAdd = (x) => { |
4 |
console.log(`The inputs are ${x} and ${y}`); |
5 |
return x+y; |
6 |
}
|
Observable Nebenwirkungen
"Observable Nebenwirkungen" ist ein ausgefallener Begriff für Interaktionen, die durch eine Funktion mit der Außenwelt hervorgerufen werden. Wenn eine Funktion versucht, einen Wert in eine Variable zu schreiben, die außerhalb der Funktion vorhanden ist, oder versucht, eine externe Methode aufzurufen, können Sie diese Nebenwirkungen sicher aufrufen.
Wenn jedoch eine reine Funktion eine andere reine Funktion aufruft, kann die Funktion als rein behandelt werden. Hier sind einige der häufigsten Nebenwirkungen:
- API-Aufrufe durchführen
- Protokollierung an der Konsole oder Drucken von Daten
- mutierende Daten
- DOM-Manipulation
- Abrufen der aktuellen Uhrzeit
Container- und Präsentationskomponenten
Das Aufteilen der Komponentenarchitektur in zwei Teile ist nützlich, wenn Sie mit React-Anwendungen arbeiten. Sie können sie grob in zwei Kategorien einteilen: Containerkomponenten und Präsentationskomponenten. Sie sind im Volksmund auch als intelligente und dumme Komponenten bekannt.
Die Containerkomponente befasst sich mit der Funktionsweise der Dinge, während sich Präsentationskomponenten mit dem Aussehen der Dinge befassen. Um die Konzepte besser zu verstehen, habe ich dies in einem anderen Tutorial behandelt: Container vs. Präsentationskomponenten in React.
Veränderbare vs. unveränderliche Objekte
Ein veränderliches Objekt kann wie folgt definiert werden:
Ein veränderbares Objekt ist ein Objekt, dessen Status nach seiner Erstellung geändert werden kann.
Unveränderlichkeit ist das genaue Gegenteil - ein unveränderliches Objekt ist ein Objekt, dessen Status nach seiner Erstellung nicht mehr geändert werden kann. In JavaScript sind Zeichenfolgen und Zahlen unveränderlich, Objekte und Arrays jedoch nicht. Das Beispiel zeigt den Unterschied besser.
1 |
/*Strings and numbers are immutable */
|
2 |
|
3 |
let a = 10; |
4 |
|
5 |
let b = a; |
6 |
|
7 |
b = 3; |
8 |
|
9 |
console.log(`a = ${a} and b = ${b} `); //a = 10 and b = 3 |
10 |
|
11 |
/* But objects and arrays are not */
|
12 |
|
13 |
/*Let's start with objects */
|
14 |
|
15 |
let user = { |
16 |
name: "Bob", |
17 |
age: 22, |
18 |
job: "None" |
19 |
}
|
20 |
|
21 |
active_user = user; |
22 |
|
23 |
active_user.name = "Tim"; |
24 |
|
25 |
//Both the objects have the same value
|
26 |
console.log(active_user); // {"name":"Tim","age":22,"job":"None"} |
27 |
|
28 |
console.log(user); // {"name":"Tim","age":22,"job":"None"} |
29 |
|
30 |
/* Now for arrays */
|
31 |
|
32 |
let usersId = [1,2,3,4,5] |
33 |
|
34 |
let usersIdDup = usersId; |
35 |
|
36 |
usersIdDup.pop(); |
37 |
|
38 |
console.log(usersIdDup); //[1,2,3,4] |
39 |
console.log(usersId); //[1,2,3,4] |
Um Objekte unveränderlich zu machen, verwenden Sie die Object.assign
-Methode, um eine neue Methode oder den neuen Spread-Operator zu erstellen.
1 |
let user = { |
2 |
name: "Bob", |
3 |
age: 22, |
4 |
job: "None" |
5 |
}
|
6 |
|
7 |
active_user = Object.assign({}, user, {name:"Tim"}) |
8 |
|
9 |
console.log(user); //{"name":"Bob","age":22,"job":"None"} |
10 |
console.log(active_user); //{"name":"Tim","age":22,"job":"None"} |
Was ist Redux?
Die offizielle Seite definiert Redux wie folgt:
Redux ist ein vorhersehbarer Statuscontainer für JavaScript-Anwendungen.
Obwohl dies Redux genau beschreibt, kann es leicht passieren, dass Sie sich verlaufen, wenn Sie zum ersten Mal das Gesamtbild von Redux sehen. Es hat so viele bewegliche Teile, dass Sie zusammenpassen müssen. Aber sobald Sie dies tun, verspreche ich Ihnen, werden Sie anfangen, Redux zu lieben.
Redux ist eine Statusverwaltungsbibliothek, die Sie mit jeder JavaScript-Bibliothek verbinden können und nicht nur mit React. Aufgrund der funktionalen Natur von React funktioniert es jedoch sehr gut mit React. Um dies besser zu verstehen, werfen wir einen Blick auf den Zustand.



Wie Sie sehen können, bestimmt der Status einer Komponente, was gerendert wird und wie sie sich verhält. Die Anwendung hat einen Anfangsstatus, und jede Benutzerinteraktion löst eine Aktion aus, die den Status aktualisiert. Wenn der Status aktualisiert wird, wird die Seite erneut gerendert.
Mit React verfügt jede Komponente über einen lokalen Status, auf den innerhalb der Komponente zugegriffen werden kann, oder Sie können sie als Requisiten an untergeordnete Komponenten weitergeben. Normalerweise verwenden wir den Status zum Speichern von:
- UI-Status und Übergangsdaten. Dies umfasst eine Liste von UI-Elementen für Navigationsmenüs oder Formulareingaben in einer gesteuerten Komponente.
- Anwendungsstatus wie von einem Server abgerufene Daten, Anmeldestatus des Benutzers usw.
Das Speichern von Anwendungsdaten im Status einer Komponente ist in Ordnung, wenn Sie eine grundlegende React-Anwendung mit wenigen Komponenten haben.



Die meisten realen Apps verfügen jedoch über viel mehr Funktionen und Komponenten. Wenn die Anzahl der Ebenen in der Komponentenhierarchie zunimmt, wird die Verwaltung des Status problematisch.



Warum sollten Sie Redux verwenden?
Hier ist ein sehr wahrscheinliches Szenario, auf das Sie bei der Arbeit mit React stoßen könnten.
- Sie erstellen eine mittelgroße Anwendung und haben Ihre Komponenten ordentlich in intelligente und dumme Komponenten aufgeteilt.
- Die intelligenten Komponenten verarbeiten den Status und geben sie dann an die dummen Komponenten weiter. Sie kümmern sich darum, API-Aufrufe durchzuführen, die Daten aus der Datenquelle abzurufen, die Daten zu verarbeiten und dann den Status festzulegen. Die dummen Komponenten erhalten die Requisiten und geben die UI-Darstellung zurück.
- Wenn Sie eine neue Komponente schreiben möchten, ist nicht immer klar, wo der Status platziert werden soll. Sie können den Status Teil eines Containers sein lassen, der ein unmittelbares übergeordnetes Element der Präsentationskomponente ist. Besser noch, Sie könnten den Status höher in der Hierarchie verschieben, sodass der Status für mehrere Präsentationskomponenten zugänglich ist.
- Wenn die App wächst, sehen Sie, dass der Status überall verstreut ist. Wenn eine Komponente auf den Status zugreifen muss, auf den sie nicht sofort Zugriff hat, versuchen Sie, den Status auf den nächsten Komponentenvorfahren anzuheben.
- Nach ständiger Umgestaltung und Bereinigung befinden sich die meisten Statushalteplätze oben in der Komponentenhierarchie.
- Schließlich entscheiden Sie, dass es eine gute Idee ist, eine Komponente an der Spitze den Status global verarbeiten zu lassen und dann alles weiterzugeben. Jede andere Komponente kann die benötigten Requisiten abonnieren und den Rest ignorieren.
Dies habe ich persönlich mit React erlebt, und viele andere Entwickler werden dem zustimmen. React ist eine Ansichtsbibliothek, und es ist nicht die Aufgabe von React, den Status spezifisch zu verwalten. Was wir suchen, ist das Prinzip der Trennung von Bedenken.
Mit Redux können Sie den Anwendungsstatus von React trennen. Redux erstellt einen globalen Speicher, der sich auf der obersten Ebene Ihrer Anwendung befindet und den Status allen anderen Komponenten zuführt. Im Gegensatz zu Flux verfügt Redux nicht über mehrere Speicherobjekte. Der gesamte Status der Anwendung befindet sich in diesem Speicherobjekt, und Sie können möglicherweise die Ansichtsebene mit einer anderen Bibliothek austauschen, wobei der Speicher intakt ist.
Die Komponenten werden jedes Mal neu gerendert, wenn der Store aktualisiert wird, ohne die Leistung zu beeinträchtigen. Das sind gute Nachrichten, und das bringt jede Menge Vorteile mit sich. Sie können alle Ihre React-Komponenten als dumm behandeln, und React kann sich nur auf die Ansichtsseite der Dinge konzentrieren.
Nachdem wir nun wissen, warum Redux nützlich ist, wollen wir uns mit der Redux-Architektur befassen.
Die Redux-Architektur
Wenn Sie Redux lernen, gibt es einige Kernkonzepte, an die Sie sich gewöhnen müssen. Das folgende Bild beschreibt die Redux-Architektur und wie alles miteinander verbunden ist.



Wenn Sie an Flux gewöhnt sind, kommen Ihnen einige Elemente möglicherweise bekannt vor. Wenn nicht, ist das auch in Ordnung, weil wir alles von der Basis aus abdecken werden. Stellen Sie zunächst sicher, dass Sie Redux installiert haben:
1 |
npm install redux
|
Verwenden Sie die create-react-app oder Ihre bevorzugte Webpack-Konfiguration, um den Entwicklungsserver einzurichten. Da Redux ein unabhängiges Statusmanagement ist, werden wir React noch nicht einbinden. Entfernen Sie also den Inhalt von index.js, und wir werden den Rest dieses Tutorials mit Redux herumspielen.
Geschäft
Der Speicher ist ein großes JavaScript-Objekt mit Tonnen von Schlüssel-Wert-Paaren, die den aktuellen Status der Anwendung darstellen. Im Gegensatz zum Statusobjekt in React, das über verschiedene Komponenten verteilt ist, haben wir nur einen Speicher. Der Speicher stellt den Anwendungsstatus bereit und jedes Mal, wenn der Status aktualisiert wird, wird die Ansicht erneut gerendert.
Sie können den Speicher jedoch niemals mutieren oder ändern. Stattdessen erstellen Sie neue Versionen des Geschäfts.
1 |
(previousState, action) => newState |
Aus diesem Grund können Sie ab dem Zeitpunkt, an dem die App in Ihrem Browser gestartet wurde, Zeitreisen durch alle Status unternehmen.
Der Speicher verfügt über drei Methoden zur Kommunikation mit dem Rest der Architektur. Sie sind:
- Store.getState() - Um auf den aktuellen Statusbaum Ihrer Anwendung zuzugreifen.
- Store.dispatch(action) - Zum Auslösen einer Statusänderung basierend auf einer Aktion. Weitere Informationen zu Aktionen finden Sie weiter unten.
- Store.subscribe(listener) - Zum Abhören von Statusänderungen. Es wird jedes Mal aufgerufen, wenn eine Aktion ausgelöst wird.
Lassen Sie uns ein Geschäft erstellen. Redux verfügt über eine createStore
-Methode zum Erstellen eines neuen Speichers. Sie müssen einen Reduzierer übergeben, obwohl wir nicht wissen, was das ist. Also werde ich einfach eine Funktion namens Reduzierer erstellen. Sie können optional ein zweites Argument angeben, das den Anfangszustand des Speichers festlegt.
src/index.js
1 |
import { createStore } from "redux"; |
2 |
// This is the reducer
|
3 |
const reducer = () => { |
4 |
/*Something goes here */
|
5 |
}
|
6 |
|
7 |
//initialState is optional.
|
8 |
//For this demo, I am using a counter, but usually state is an object
|
9 |
const initialState = 0 |
10 |
const store = createStore(reducer, initialState); |
Jetzt werden wir alle Änderungen im Store abhören und dann console.log()
den aktuellen Status des Stores anzeigen.
1 |
store.subscribe( () => { |
2 |
console.log("State has changed" + store.getState()); |
3 |
})
|
Wie aktualisieren wir den Store? Redux hat so genannte Aktionen, die dies ermöglichen.
Aktion/Aktionsersteller
Aktionen sind auch einfache JavaScript-Objekte, die Informationen aus Ihrer Anwendung an den Store senden. Wenn Sie einen sehr einfachen Zähler mit einer Inkrement-Taste haben, wird durch Drücken dieser Taste eine Aktion ausgelöst, die folgendermaßen aussieht:
1 |
{
|
2 |
type: "INCREMENT", |
3 |
payload: 1 |
4 |
}
|
Sie sind die einzige Informationsquelle für das Geschäft. Der Status des Speichers ändert sich nur als Reaktion auf eine Aktion. Jede Aktion sollte eine type-Eigenschaft haben, die beschreibt, was das Aktionsobjekt beabsichtigt. Davon abgesehen liegt die Struktur der Aktion ganz bei Ihnen. Halten Sie Ihre Aktion jedoch klein, da eine Aktion die Mindestmenge an Informationen darstellt, die zum Transformieren des Anwendungsstatus erforderlich sind.
Im obigen Beispiel wird beispielsweise die type-Eigenschaft auf "INCREMENT" gesetzt, und eine zusätzliche Payload-Eigenschaft ist enthalten. Sie können die Payload-Eigenschaft in eine aussagekräftigere umbenennen oder in unserem Fall ganz weglassen. Sie können eine Aktion wie folgt an das Geschäft senden.
1 |
store.dispatch({type: "INCREMENT", payload: 1}); |
Beim Codieren von Redux werden Sie normalerweise keine Aktionen direkt verwenden. Stattdessen rufen Sie Funktionen auf, die Aktionen zurückgeben. Diese Funktionen werden im Allgemeinen als Aktionsersteller bezeichnet. Hier ist der Aktionsersteller für die zuvor beschriebene Inkrementierungsaktion.
1 |
const incrementCount = (count) => { |
2 |
return { |
3 |
type: "INCREMENT", |
4 |
payload: count |
5 |
}
|
6 |
}
|
Um den Status des Zählers zu aktualisieren, müssen Sie die Aktion incrementCount
wie folgt auslösen:
1 |
store.dispatch(incrementCount(1)); |
2 |
store.dispatch(incrementCount(1)); |
3 |
store.dispatch(incrementCount(1)); |
Wenn Sie zur Browserkonsole gehen, werden Sie feststellen, dass sie teilweise funktioniert. Wir werden undefiniert, weil wir den Reduzierer noch nicht definiert haben.



Jetzt haben wir also die Aktionen und den Laden behandelt. Wir benötigen jedoch einen Mechanismus, um die von der Aktion bereitgestellten Informationen zu konvertieren und den Status des Speichers zu transformieren. Reduzierstücke dienen diesem Zweck.
Reduzierstücke
Eine Aktion beschreibt das Problem, und der Reduzierer ist für die Lösung des Problems verantwortlich. Im vorherigen Beispiel hat die Methode incrementCount
eine Aktion zurückgegeben, die Informationen über die Art der Änderung lieferte, die wir am Status vornehmen wollten. Der Reduzierer verwendet diese Informationen, um den Status tatsächlich zu aktualisieren. In den Dokumenten wird ein wichtiger Punkt hervorgehoben, an den Sie sich bei der Verwendung von Redux immer erinnern sollten:
Mit den gleichen Argumenten sollte ein Reduzierer den nächsten Zustand berechnen und zurückgeben. Keine Überraschungen. Keine Nebenwirkungen. Keine API-Aufrufe. Keine Mutationen. Nur eine Berechnung.
Dies bedeutet, dass ein Reduzierstück eine reine Funktion sein sollte. Bei einer Reihe von Eingaben sollte immer dieselbe Ausgabe zurückgegeben werden. Darüber hinaus sollte es nichts mehr tun. Ein Reduzierer ist auch nicht der Ort für Nebenwirkungen wie AJAX-Aufrufe oder das Abrufen von Daten von der API.
Füllen wir den Reduzierer für unseren Zähler aus.
1 |
// This is the reducer
|
2 |
|
3 |
const reducer = (state = initialState, action) => { |
4 |
switch (action.type) { |
5 |
case "INCREMENT": |
6 |
return state + action.payload |
7 |
default: |
8 |
return state |
9 |
}
|
10 |
}
|
Der Reduzierer akzeptiert zwei Argumente - Status und Aktion - und gibt einen neuen Status zurück.
1 |
(previousState, action) => newState |
Der Status akzeptiert einen Standardwert, den initialState
, der nur verwendet wird, wenn der Wert des Status undefiniert ist. Andernfalls bleibt der tatsächliche Wert des Zustands erhalten. Wir verwenden die switch-Anweisung, um die richtige Aktion auszuwählen. Aktualisieren Sie den Browser und alles funktioniert wie erwartet.
Fügen wir einen Fall für DECREMENT
hinzu, ohne den der Zähler unvollständig ist.
1 |
// This is the reducer
|
2 |
|
3 |
const reducer = (state = initialState, action) => { |
4 |
switch (action.type) { |
5 |
case "INCREMENT": |
6 |
return state + action.payload |
7 |
case "DECREMENT": |
8 |
return state - action.payload |
9 |
default: |
10 |
return state |
11 |
}
|
12 |
}
|
Hier ist der Action Creator.
1 |
const decrementCount = (count) => { |
2 |
return { |
3 |
type: "DECREMENT", |
4 |
payload: count |
5 |
}
|
6 |
}
|
Zum Schluss versenden Sie es in den Laden.
1 |
store.dispatch(incrementCount(4)); //4 |
2 |
store.dispatch(decrementCount(2)); //2 |
Das ist es!
Zusammenfassung
Dieses Tutorial sollte als Ausgangspunkt für die Verwaltung des Status mit Redux dienen. Wir haben alles Notwendige behandelt, um die grundlegenden Redux-Konzepte wie Store, Aktionen und Reduzierungen zu verstehen. Gegen Ende des Tutorials haben wir auch einen funktionierenden Redux-Demo-Zähler erstellt. Obwohl es nicht viel war, haben wir gelernt, wie alle Teile des Puzzles zusammenpassen.
In den letzten Jahren hat React an Popularität gewonnen. Tatsächlich haben wir eine Reihe von Artikeln auf dem Markt, die zum Kauf, zur Überprüfung, Implementierung usw. verfügbar sind. Wenn Sie nach zusätzlichen Ressourcen rund um React suchen, zögern Sie nicht, diese zu überprüfen.
Im nächsten Tutorial werden wir die Dinge, die wir hier gelernt haben, verwenden, um eine React-Anwendung mit Redux zu erstellen. Bleib bis dahin dran. Teilen Sie Ihre Gedanken in den Kommentaren.