Laut den Dokumenten, „ohne Middleware, Redux Speicher unterstützen nur synchronen Datenfluss“ . Ich verstehe nicht, warum das so ist. Warum kann die Containerkomponente nicht die asynchrone API und dann dispatch
die Aktionen aufrufen ?
Stellen Sie sich zum Beispiel eine einfache Benutzeroberfläche vor: ein Feld und eine Schaltfläche. Wenn der Benutzer die Taste drückt, wird das Feld mit Daten von einem Remote-Server gefüllt.
import * as React from 'react';
import * as Redux from 'redux';
import { Provider, connect } from 'react-redux';
const ActionTypes = {
STARTED_UPDATING: 'STARTED_UPDATING',
UPDATED: 'UPDATED'
};
class AsyncApi {
static getFieldValue() {
const promise = new Promise((resolve) => {
setTimeout(() => {
resolve(Math.floor(Math.random() * 100));
}, 1000);
});
return promise;
}
}
class App extends React.Component {
render() {
return (
<div>
<input value={this.props.field}/>
<button disabled={this.props.isWaiting} onClick={this.props.update}>Fetch</button>
{this.props.isWaiting && <div>Waiting...</div>}
</div>
);
}
}
App.propTypes = {
dispatch: React.PropTypes.func,
field: React.PropTypes.any,
isWaiting: React.PropTypes.bool
};
const reducer = (state = { field: 'No data', isWaiting: false }, action) => {
switch (action.type) {
case ActionTypes.STARTED_UPDATING:
return { ...state, isWaiting: true };
case ActionTypes.UPDATED:
return { ...state, isWaiting: false, field: action.payload };
default:
return state;
}
};
const store = Redux.createStore(reducer);
const ConnectedApp = connect(
(state) => {
return { ...state };
},
(dispatch) => {
return {
update: () => {
dispatch({
type: ActionTypes.STARTED_UPDATING
});
AsyncApi.getFieldValue()
.then(result => dispatch({
type: ActionTypes.UPDATED,
payload: result
}));
}
};
})(App);
export default class extends React.Component {
render() {
return <Provider store={store}><ConnectedApp/></Provider>;
}
}
Wenn die exportierte Komponente gerendert wird, kann ich auf die Schaltfläche klicken und die Eingabe wird korrekt aktualisiert.
Beachten Sie die update
Funktion in derconnect
Aufruf. Es löst eine Aktion aus, die der App mitteilt, dass sie aktualisiert wird, und führt dann einen asynchronen Aufruf aus. Nach Beendigung des Aufrufs wird der angegebene Wert als Nutzlast einer anderen Aktion gesendet.
Was ist falsch an diesem Ansatz? Warum sollte ich Redux Thunk oder Redux Promise verwenden, wie in der Dokumentation vorgeschlagen?
BEARBEITEN: Ich habe das Redux-Repo nach Hinweisen durchsucht und festgestellt, dass Action Creators in der Vergangenheit reine Funktionen sein mussten. Hier ist beispielsweise ein Benutzer, der versucht, eine bessere Erklärung für den asynchronen Datenfluss bereitzustellen:
Der Aktionsersteller selbst ist immer noch eine reine Funktion, aber die zurückgegebene Thunk-Funktion muss es nicht sein, und er kann unsere asynchronen Aufrufe ausführen
Action-Ersteller müssen nicht mehr rein sein. Thunk / Promise-Middleware war in der Vergangenheit definitiv erforderlich, aber es scheint, dass dies nicht mehr der Fall ist?
quelle
Antworten:
An diesem Ansatz ist nichts auszusetzen. In einer großen Anwendung ist dies nur unpraktisch, da verschiedene Komponenten dieselben Aktionen ausführen. Möglicherweise möchten Sie einige Aktionen entprellen oder einen lokalen Status wie das automatische Inkrementieren von IDs in der Nähe von Aktionserstellern usw. beibehalten. Dies ist also einfacher die Wartungsperspektive, um Aktionsersteller in separate Funktionen zu extrahieren.
Sie können meine Antwort auf "So senden Sie eine Redux-Aktion mit einer Zeitüberschreitung" lesen, um eine detailliertere Anleitung zu erhalten.
Middleware wie Redux Thunk oder Redux Versprechen gibt Ihnen nur „Syntax Zucker“ für Thunks oder Versprechen Disposition, aber Sie nicht haben zu verwenden.
Ohne Middleware könnte Ihr Action Creator also so aussehen
Aber mit Thunk Middleware können Sie es so schreiben:
Es gibt also keinen großen Unterschied. Eine Sache, die ich an letzterem Ansatz mag, ist, dass es der Komponente egal ist, dass der Aktionsersteller asynchron ist. Es wird nur
dispatch
normal aufgerufen, es kann auch verwendet werdenmapDispatchToProps
, um einen solchen Aktionsersteller mit einer kurzen Syntax usw. zu binden. Die Komponenten wissen nicht, wie Aktionsersteller implementiert sind, und Sie können zwischen verschiedenen asynchronen Ansätzen (Redux Thunk, Redux Promise, Redux Saga) wechseln ) ohne die Komponenten zu wechseln. Auf der anderen Seite wissen Ihre Komponenten mit dem früheren expliziten Ansatz genau, dass ein bestimmter Aufruf asynchron ist und benötigt wirddispatch
von einer Konvention übergeben werden muss (z. B. als Synchronisierungsparameter).Denken Sie auch darüber nach, wie sich dieser Code ändern wird. Angenommen, wir möchten eine zweite Funktion zum Laden von Daten haben und diese in einem einzigen Aktionsersteller kombinieren.
Beim ersten Ansatz müssen wir uns bewusst sein, welche Art von Aktionsersteller wir nennen:
Mit Redux Thunk können Aktionsersteller
dispatch
das Ergebnis anderer Aktionsersteller sein und nicht einmal darüber nachdenken, ob diese synchron oder asynchron sind:Wenn Sie später möchten, dass Ihre Aktionsersteller den aktuellen Redux-Status
getState
anzeigen , können Sie bei diesem Ansatz einfach das zweite Argument verwenden, das an die Thunks übergeben wird, ohne den aufrufenden Code zu ändern:Wenn Sie es ändern müssen, um synchron zu sein, können Sie dies auch tun, ohne einen aufrufenden Code zu ändern:
Der Vorteil der Verwendung von Middleware wie Redux Thunk oder Redux Promise besteht darin, dass Komponenten nicht wissen, wie Aktionsersteller implementiert sind, ob ihnen der Redux-Status wichtig ist, ob sie synchron oder asynchron sind und ob sie andere Aktionsersteller aufrufen oder nicht . Der Nachteil ist ein bisschen Indirektion, aber wir glauben, dass es sich in realen Anwendungen lohnt.
Schließlich ist Redux Thunk und Freunde nur ein möglicher Ansatz für asynchrone Anforderungen in Redux-Apps. Ein weiterer interessanter Ansatz ist Redux Saga, mit dem Sie lang laufende Dämonen („Sagas“) definieren können, die Aktionen sofort ausführen und Anforderungen transformieren oder ausführen, bevor Sie Aktionen ausgeben. Dies verschiebt die Logik von Aktionserstellern in Sagen. Vielleicht möchten Sie es ausprobieren und später auswählen, was am besten zu Ihnen passt.
Das ist falsch. Die Dokumente sagten dies, aber die Dokumente waren falsch.
Action Creators mussten niemals reine Funktionen sein.
Wir haben die Dokumente korrigiert, um dies widerzuspiegeln.
quelle
alert
nachdispatch()
der Aktion ing.loadData(this.props.dispatch, this.props.userId); // don't forget to pass dispatch
. Warum muss ich den Versand übergeben? Wenn es konventionell immer nur einen einzigen globalen Speicher gibt, warum verweise ichstore.dispatch
dann nicht einfach direkt darauf und wann immer ich muss, z. B. inloadData
?store
für jede Anforderung eine andere Instanz haben, damit Sie sie nicht vorher definieren können.Das tust du nicht.
Aber ... du solltest Redux-Saga verwenden :)
Dan Abramovs Antwort ist richtig,
redux-thunk
aber ich werde ein bisschen mehr über Redux-Saga sprechen , die ziemlich ähnlich, aber mächtiger ist.Imperativ VS deklarativ
redux-thunk
sind zwingend /redux-saga
deklarativWenn Sie einen Thunk in Ihren Händen haben, wie eine IO-Monade oder ein Versprechen, können Sie nicht leicht wissen, was es tun wird, wenn Sie es ausführen. Die einzige Möglichkeit, einen Thunk zu testen, besteht darin, ihn auszuführen und den Dispatcher (oder die gesamte Außenwelt, wenn er mit mehr Dingen interagiert ...) zu verspotten.
Wenn Sie Mocks verwenden, führen Sie keine funktionale Programmierung durch.
Quelle
Die Sagen (wie sie in implementiert wurden
redux-saga
) sind deklarativ und wie die Komponenten Free Monad oder React viel einfacher zu testen, ohne sich zu verspotten.Siehe auch diesen Artikel :
(Eigentlich ist die Redux-Saga wie ein Hybrid: Der Fluss ist zwingend, aber die Auswirkungen sind deklarativ.)
Verwirrung: Aktionen / Ereignisse / Befehle ...
In der Frontend-Welt herrscht große Verwirrung darüber, wie einige Backend-Konzepte wie CQRS / EventSourcing und Flux / Redux zusammenhängen können, vor allem, weil wir in Flux den Begriff "Aktion" verwenden, der manchmal sowohl imperativen Code (
LOAD_USER
) als auch Ereignisse () darstellen kannUSER_LOADED
). Ich glaube, dass Sie wie beim Event-Sourcing nur Events versenden sollten.Verwenden von Sagen in der Praxis
Stellen Sie sich eine App mit einem Link zu einem Benutzerprofil vor. Der idiomatische Weg, dies mit jeder Middleware zu handhaben, wäre:
redux-thunk
redux-saga
Diese Saga übersetzt zu:
Wie Sie sehen können, gibt es einige Vorteile von
redux-saga
.Die Verwendung von
takeLatest
Genehmigungen, um auszudrücken, dass Sie nur daran interessiert sind, die Daten des letzten angeklickten Benutzernamens zu erhalten (behandeln Sie Parallelitätsprobleme, falls der Benutzer sehr schnell auf viele Benutzernamen klickt). Diese Art von Sachen ist schwer mit Thunks. Sie hätten verwenden können,takeEvery
wenn Sie dieses Verhalten nicht möchten.Sie halten Action-Schöpfer rein. Beachten Sie, dass es immer noch nützlich ist, actionCreators (in Sagen
put
und Komponenten) beizubehaltendispatch
) , da dies Ihnen möglicherweise helfen wird, die Aktionsvalidierung (Assertions / Flow / Typoskript) in Zukunft hinzuzufügen.Ihr Code wird viel testbarer, da die Auswirkungen deklarativ sind
Sie müssen keine rpc-ähnlichen Aufrufe mehr auslösen
actions.loadUser()
. Ihre Benutzeroberfläche muss nur das versenden, was geschehen ist. Wir feuern nur noch Ereignisse ab (immer in der Vergangenheitsform!) Und keine Aktionen mehr. Dies bedeutet, dass Sie entkoppelte "Enten" oder begrenzte Kontexte erstellen können und dass die Saga als Kopplungspunkt zwischen diesen modularen Komponenten fungieren kann.Dies bedeutet, dass Ihre Ansichten einfacher zu verwalten sind, da sie diese Übersetzungsebene zwischen dem, was passiert ist und dem, was als Effekt passieren sollte, nicht mehr enthalten müssen
Stellen Sie sich zum Beispiel eine unendliche Bildlaufansicht vor.
CONTAINER_SCROLLED
Kann führen zuNEXT_PAGE_LOADED
, aber liegt es wirklich in der Verantwortung des scrollbaren Containers, zu entscheiden, ob wir eine andere Seite laden sollen oder nicht? Dann muss er sich komplizierterer Dinge bewusst sein, z. B. ob die letzte Seite erfolgreich geladen wurde oder ob bereits eine Seite geladen werden soll oder ob keine weiteren Elemente mehr geladen werden müssen. Ich denke nicht: Für maximale Wiederverwendbarkeit sollte der scrollbare Container nur beschreiben, dass er gescrollt wurde. Das Laden einer Seite ist ein "Geschäftseffekt" dieser SchriftrolleEinige mögen argumentieren, dass Generatoren den Status außerhalb des Redux-Speichers mit lokalen Variablen von Natur aus verbergen können, aber wenn Sie anfangen, komplexe Dinge innerhalb von Thunks durch Starten von Timern usw. zu orchestrieren, hätten Sie sowieso das gleiche Problem. Und es gibt einen
select
Effekt, der es jetzt ermöglicht, einen Status aus Ihrem Redux-Shop abzurufen.Sagas können zeitlich begrenzt sein und ermöglichen auch komplexe Flow-Logging- und Dev-Tools, an denen derzeit gearbeitet wird. Hier ist eine einfache asynchrone Flussprotokollierung, die bereits implementiert ist:
Entkopplung
Sagas ersetzen nicht nur Redux-Thunks. Sie stammen aus dem Backend / verteilten Systemen / Event-Sourcing.
Es ist ein weit verbreitetes Missverständnis, dass Sagen nur dazu da sind, Ihre Redux-Thunks durch bessere Testbarkeit zu ersetzen. Eigentlich ist dies nur ein Implementierungsdetail der Redux-Saga. Die Verwendung deklarativer Effekte ist aus Gründen der Testbarkeit besser als Thunks, aber das Saga-Muster kann zusätzlich zu imperativem oder deklarativem Code implementiert werden.
Erstens ist die Saga eine Software, die es ermöglicht, lang laufende Transaktionen (eventuelle Konsistenz) und Transaktionen über verschiedene begrenzte Kontexte hinweg (domänengesteuerte Designsprache) zu koordinieren.
Stellen Sie sich vor, es gibt Widget1 und Widget2, um dies für die Frontend-Welt zu vereinfachen. Wenn auf eine Schaltfläche in Widget1 geklickt wird, sollte dies Auswirkungen auf Widget2 haben. Anstatt die beiden Widgets miteinander zu koppeln (dh Widget1 löst eine Aktion aus, die auf Widget2 abzielt), sendet Widget1 nur, dass auf die Schaltfläche geklickt wurde. Dann wartet die Saga auf diese Schaltfläche, klickt und aktualisiert dann Widget2, indem ein neues Ereignis entfernt wird, das Widget2 kennt.
Dies fügt eine Indirektionsebene hinzu, die für einfache Apps nicht erforderlich ist, die Skalierung komplexer Anwendungen jedoch einfacher macht. Sie können jetzt Widget1 und Widget2 in verschiedenen npm-Repositorys veröffentlichen, sodass sie sich nie gegenseitig kennen müssen, ohne dass sie eine globale Aktionsregistrierung gemeinsam nutzen müssen. Die 2 Widgets sind jetzt begrenzte Kontexte, die separat leben können. Sie müssen nicht konsistent sein und können auch in anderen Apps wiederverwendet werden. Die Saga ist der Kopplungspunkt zwischen den beiden Widgets, die sie auf sinnvolle Weise für Ihr Unternehmen koordinieren.
Einige nette Artikel zur Strukturierung Ihrer Redux-App, in denen Sie die Redux-Saga aus Gründen der Entkopplung verwenden können:
Ein konkreter Anwendungsfall: Benachrichtigungssystem
Ich möchte, dass meine Komponenten die Anzeige von In-App-Benachrichtigungen auslösen können. Ich möchte jedoch nicht, dass meine Komponenten in hohem Maße an das Benachrichtigungssystem gekoppelt sind, das über eigene Geschäftsregeln verfügt (maximal 3 Benachrichtigungen werden gleichzeitig angezeigt, Benachrichtigungswarteschlange, 4 Sekunden Anzeigezeit usw.).
Ich möchte nicht, dass meine JSX-Komponenten entscheiden, wann eine Benachrichtigung angezeigt / ausgeblendet wird. Ich gebe ihm nur die Möglichkeit, eine Benachrichtigung anzufordern und die komplexen Regeln in der Saga zu belassen. Diese Art von Sachen ist mit Thunks oder Versprechungen ziemlich schwer umzusetzen.
Ich habe hier beschrieben , wie dies mit Saga gemacht werden kann
Warum heißt es Saga?
Der Begriff Saga stammt aus der Backend-Welt. Ich habe Yassine (den Autor der Redux-Saga) in einer langen Diskussion zunächst mit diesem Begriff bekannt gemacht .
Ursprünglich wurde dieser Begriff mit einem Papier eingeführt . Das Saga-Muster sollte verwendet werden, um eventuelle Konsistenz bei verteilten Transaktionen zu behandeln. Die Verwendung wurde jedoch von Backend-Entwicklern auf eine breitere Definition erweitert, sodass es jetzt auch den "Prozessmanager" abdeckt. Muster (irgendwie ist das ursprüngliche Saga-Muster eine spezielle Form des Prozessmanagers).
Heute ist der Begriff "Saga" verwirrend, da er zwei verschiedene Dinge beschreiben kann. Da es in der Redux-Saga verwendet wird, beschreibt es keine Möglichkeit, verteilte Transaktionen zu verarbeiten, sondern eine Möglichkeit, Aktionen in Ihrer App zu koordinieren.
redux-saga
hätte auch angerufen werden könnenredux-process-manager
.Siehe auch:
Alternativen
Wenn Sie die Idee der Verwendung von Generatoren nicht mögen, sich aber für das Saga-Muster und seine Entkopplungseigenschaften interessieren, können Sie dasselbe auch mit redux-beobachtbar erreichen , das den Namen verwendet
epic
, um genau dasselbe Muster zu beschreiben, jedoch mit RxJS. Wenn Sie bereits mit Rx vertraut sind, werden Sie sich wie zu Hause fühlen.Einige nützliche Ressourcen der Redux-Saga
2017 rät
yield put(someActionThunk)
wenn es Sinn macht.Wenn Sie Angst haben, Redux-Saga (oder Redux-Observable) zu verwenden, aber nur das Entkopplungsmuster benötigen, überprüfen Sie Redux-Dispatch-Subscribe : Es ermöglicht das Abhören von Sendungen und das Auslösen neuer Sendungen im Listener.
quelle
ADD_ITEM
, ist dies unbedingt erforderlich, da Sie eine Aktion versenden, die sich auf Ihr Geschäft auswirken soll: Sie erwarten, dass die Aktion etwas bewirkt. Als deklarativ bezeichnen Sie die Philosophie des Event-Sourcing: Sie senden keine Aktionen aus, um Änderungen an Ihren Anwendungen auszulösen, sondern Sie senden vergangene Ereignisse aus, um zu beschreiben, was in Ihrer Anwendung passiert ist. Der Versand eines Ereignisses sollte ausreichen, um zu berücksichtigen, dass sich der Status der Anwendung geändert hat. Die Tatsache, dass es einen Redux-Store gibt, der auf Ereignisse reagiert, ist ein optionales ImplementierungsdetailDie kurze Antwort : scheint mir ein völlig vernünftiger Ansatz für das Asynchronitätsproblem zu sein. Mit ein paar Einschränkungen.
Ich hatte einen sehr ähnlichen Gedankengang, als ich an einem neuen Projekt arbeitete, das wir gerade bei meiner Arbeit begonnen hatten. Ich war ein großer Fan von Vanilla Redux 'elegantem System zur Aktualisierung des Geschäfts und zum erneuten Rendern von Komponenten auf eine Weise, die sich aus den Eingeweiden eines React-Komponentenbaums heraushält. Es kam mir komisch vor, mich in diesen eleganten
dispatch
Mechanismus zu integrieren, um mit Asynchronität umzugehen.Am Ende hatte ich einen wirklich ähnlichen Ansatz wie in einer Bibliothek, die ich aus unserem Projekt herausgerechnet habe, das wir React-Redux-Controller nannten .
Ich bin aus mehreren Gründen nicht mit dem genauen Ansatz vorgegangen, den Sie oben haben:
dispatch
über den lexikalischen Bereich Zugriff auf sich selbst. Dies schränkt die Optionen für das Refactoring ein, sobald dieseconnect
Anweisung außer Kontrolle gerät - und sie sieht mit nur dieser einenupdate
Methode ziemlich unhandlich aus . Sie benötigen also ein System, mit dem Sie diese Dispatcher-Funktionen zusammenstellen können, wenn Sie sie in separate Module aufteilen.Zusammengenommen müssen Sie ein System aufbauen, damit
dispatch
das Geschäft zusammen mit den Parametern des Ereignisses in Ihre Versandfunktionen eingefügt werden kann. Ich kenne drei vernünftige Ansätze für diese Abhängigkeitsinjektion:dispatch
Middleware-Ansätzen gearbeitet, aber ich gehe davon aus, dass sie im Grunde gleich sind.connect
, anstatt direkt mit dem rohen, normalisierten Speicher arbeiten zu müssen.this
über eine Vielzahl möglicher Mechanismen in den Kontext einfügen.Aktualisieren
Mir fällt ein, dass ein Teil dieses Rätsels eine Einschränkung des React -Redux ist . Das erste Argument, um
connect
einen Status-Snapshot zu erhalten, aber keinen Versand. Das zweite Argument wird versandt, aber nicht der Staat. Keines der Argumente erhält einen Thunk, der über dem aktuellen Status geschlossen wird, um den aktualisierten Status zum Zeitpunkt einer Fortsetzung / eines Rückrufs anzeigen zu können.quelle
Abramovs Ziel - und im Idealfall jeder - ist es einfach, Komplexität (und asynchrone Anrufe) an dem Ort zusammenzufassen, an dem sie am besten geeignet ist .
Wo ist der beste Ort, um dies im Standard-Redux-Datenfluss zu tun? Wie wäre es mit:
quelle
Um die am Anfang gestellte Frage zu beantworten:
Beachten Sie, dass diese Dokumente für Redux und nicht für Redux plus React bestimmt sind. Redux-Stores, die an React-Komponenten angeschlossen sind, können genau das tun, was Sie sagen, aber ein Plain Jane Redux-Store ohne Middleware akzeptiert keine Argumente,
dispatch
außer für einfache alte Objekte.Ohne Middleware könnte man das natürlich noch machen
In einem ähnlichen Fall wird die Asynchronität jedoch um Redux gewickelt und nicht von Redux verarbeitet. Middleware ermöglicht also Asynchronität, indem geändert wird, was direkt an übergeben werden kann
dispatch
.Der Geist Ihres Vorschlags ist jedoch meiner Meinung nach gültig. Es gibt sicherlich andere Möglichkeiten, wie Sie mit Asynchronität in einer Redux + React-Anwendung umgehen können.
Ein Vorteil der Verwendung von Middleware besteht darin, dass Sie weiterhin wie gewohnt Action Creators verwenden können, ohne sich Gedanken darüber machen zu müssen, wie sie genau angeschlossen sind. Wenn Sie beispielsweise
redux-thunk
den von Ihnen geschriebenen Code verwenden, sieht er sehr ähnlich ausDas sieht nicht viel anders aus als das Original - es wird nur ein bisschen gemischt - und
connect
weiß nicht, dassupdateThing
es asynchron ist (oder sein muss).Wenn Sie auch Versprechen , Observablen , Sagen oder verrückte benutzerdefinierte und äußerst deklarative Aktionsersteller unterstützen möchten, kann Redux dies tun, indem Sie einfach ändern, an was Sie übergeben
dispatch
(auch bekannt als das, was Sie von Aktionserstellern zurückgeben). Kein Mist mit den React-Komponenten (oderconnect
Aufrufen) notwendig.quelle
OK, lassen Sie uns zuerst sehen, wie Middleware funktioniert, die die Frage ganz beantwortet. Dies ist der Quellcode einer pplyMiddleWare- Funktion in Redux:
Schauen Sie sich diesen Teil an und sehen Sie, wie unser Versand zu einer Funktion wird .
OK, so stellt sich Redux-thunk als eine der am häufigsten verwendeten Middlewares für Redux vor:
Wie Sie sehen, wird eine Funktion anstelle einer Aktion zurückgegeben. Sie können also warten und sie jederzeit aufrufen, da es sich um eine Funktion handelt.
Also, was zum Teufel ist das? So wird es in Wikipedia eingeführt:
Sehen Sie also, wie einfach das Konzept ist und wie es Ihnen bei der Verwaltung Ihrer asynchronen Aktionen helfen kann ...
Das ist etwas, ohne das man leben kann, aber denken Sie daran, dass es beim Programmieren immer bessere, sauberere und richtige Wege gibt, Dinge zu tun ...
quelle
Die Verwendung von Redux-saga ist die beste Middleware für die Implementierung von React-redux.
Beispiel: store.js
Und dann saga.js
Und dann action.js
Und dann reducer.js
Und dann main.js
versuchen Sie dies .. funktioniert
quelle
Es gibt synchrone Aktionsersteller und dann asynchrone Aktionsersteller.
Ein synchroner Aktionsersteller ist einer, der beim Aufrufen sofort ein Aktionsobjekt mit allen relevanten Daten zurückgibt, die an dieses Objekt angehängt sind, und bereit ist, von unseren Reduzierungen verarbeitet zu werden.
Asynchrone Aktionsersteller benötigen einige Zeit, bis sie zum endgültigen Versenden einer Aktion bereit sind.
Per Definition gilt ein Aktionsersteller, der eine Netzwerkanforderung stellt, immer als asynchroner Aktionsersteller.
Wenn Sie asynchrone Aktionsersteller in einer Redux-Anwendung haben möchten, müssen Sie eine sogenannte Middleware installieren, mit der Sie mit diesen asynchronen Aktionserstellern umgehen können.
Sie können dies in der Fehlermeldung überprüfen, die besagt, dass wir benutzerdefinierte Middleware für asynchrone Aktionen verwenden.
Was ist eine Middleware und warum benötigen wir sie für den asynchronen Ablauf in Redux?
Im Kontext von Redux-Middleware wie Redux-Thunk hilft uns eine Middleware beim Umgang mit asynchronen Aktionserstellern, da Redux dies nicht sofort tun kann.
Mit einer Middleware, die in den Redux-Zyklus integriert ist, rufen wir immer noch Aktionsersteller an, die eine Aktion zurückgeben, die ausgelöst wird. Wenn wir jedoch eine Aktion senden, anstatt sie direkt an alle unsere Reduzierer zu senden, werden wir loslegen um zu sagen, dass eine Aktion über die gesamte Middleware in der Anwendung gesendet wird.
Innerhalb einer einzelnen Redux-App können wir so viele oder so wenige Middleware haben, wie wir möchten. In den Projekten, an denen wir arbeiten, werden größtenteils eine oder zwei Middleware an unseren Redux-Store angeschlossen.
Eine Middleware ist eine einfache JavaScript-Funktion, die bei jeder einzelnen Aktion, die wir auslösen, aufgerufen wird. Innerhalb dieser Funktion hat eine Middleware die Möglichkeit, zu verhindern, dass eine Aktion an einen der Reduzierer gesendet wird. Sie kann eine Aktion ändern oder einfach mit einer Aktion herumspielen, wie Sie es beispielsweise tun. Wir könnten beispielsweise eine Middleware erstellen, die die Konsole protokolliert Jede Aktion, die Sie nur zu Ihrem Vergnügen versenden.
Es gibt eine enorme Anzahl von Open Source-Middleware, die Sie als Abhängigkeiten in Ihr Projekt installieren können.
Sie können nicht nur Open Source-Middleware verwenden oder diese als Abhängigkeiten installieren. Sie können Ihre eigene benutzerdefinierte Middleware schreiben und in Ihrem Redux-Store verwenden.
Eine der beliebtesten Anwendungen von Middleware (und das Erreichen Ihrer Antwort) ist der Umgang mit asynchronen Aktionserstellern. Die wahrscheinlich beliebteste Middleware auf dem Markt ist Redux-Thunk, und es geht darum, Ihnen beim Umgang mit asynchronen Aktionserstellern zu helfen.
Es gibt viele andere Arten von Middleware, die Ihnen auch beim Umgang mit asynchronen Aktionserstellern helfen.
quelle
Um die Frage zu beantworten:
Ich würde aus mindestens zwei Gründen sagen:
Der erste Grund ist die Trennung von Bedenken, es ist nicht die Aufgabe der, die
action creator
aufzurufenapi
und Daten zurückzubekommen, Sie müssen zwei Argumente an Ihreaction creator function
, dieaction type
und eine übergebenpayload
.Der zweite Grund ist, dass das
redux store
auf ein einfaches Objekt mit obligatorischem Aktionstyp und optional a wartetpayload
(aber hier müssen Sie auch die Nutzdaten übergeben).Der Aktionsersteller sollte ein einfaches Objekt wie das folgende sein:
Und die Aufgabe
Redux-Thunk midleware
,dispache
das Ergebnis von Ihnenapi call
zu den entsprechendenaction
.quelle
Wenn Sie in einem Unternehmensprojekt arbeiten, stehen in Middleware viele Anforderungen zur Verfügung, z. B. (Saga), die im einfachen asynchronen Ablauf nicht verfügbar sind. Nachfolgend einige:
Die Liste ist lang. Lesen Sie einfach den erweiterten Abschnitt in der Saga-Dokumentation
quelle