Redux: Empfehlen Sie, dass Action-Konstanten in der Vergangenheitsform benannt werden

Erstellt am 1. Aug. 2015  ·  55Kommentare  ·  Quelle: reduxjs/redux

Da Nr. 377 (aus gültigen Ökosystemgründen) geschlossen wurde, wie wäre es, wenn Sie in der Dokumentation empfehlen, anstelle von INCREASE_COUNT besser COUNT_INCREASED zu schreiben?

Auf diese Weise wird man weniger versucht sein, Nebenwirkungen in Reduktionsmitteln zu stecken.

Hilfreichster Kommentar

Ich bin (noch) nicht überzeugt, aber offen, um überzeugt zu werden.
Für mich sind Aktionen eine Absicht, der Reduzierer möchte möglicherweise nicht inkrementieren, daher fühlt sich COUNT_INCREASED dann irgendwie seltsam an.
Außerdem hat { type: 'COUNT_INCREASED', data: 2 } eine ganz andere Bedeutung ("increased to 2") als { type: 'INCREASE_COUNT', data: 2 } ("increase by 2").

Alle 55 Kommentare

Das klingt für mich vernünftig!

Ich stimme zu :+1:

Ich bin (noch) nicht überzeugt, aber offen, um überzeugt zu werden.
Für mich sind Aktionen eine Absicht, der Reduzierer möchte möglicherweise nicht inkrementieren, daher fühlt sich COUNT_INCREASED dann irgendwie seltsam an.
Außerdem hat { type: 'COUNT_INCREASED', data: 2 } eine ganz andere Bedeutung ("increased to 2") als { type: 'INCREASE_COUNT', data: 2 } ("increase by 2").

Im Fall von BUTTON_PUSHED ist es sinnvoll - aber ich stimme nicht zu, dass INCREASE_COUNT zu COUNT_INCREASED werden sollte - die Anzahl wird nicht erhöht, wenn das AC diese Aktion erstellt.

Ich war nicht sofort überzeugt. Ich muss über die Idee nachdenken.

Tatsächlich wäre der vollständige Name in diesem Fall COUNT_INCREASE_REQUESTED,
die zwar etwas lang ist, aber immer noch die eigentliche Absicht vermittelt.

COUNT_INC_REQD?

Am Sonntag, 2. August 2015, 04:12 Uhr schrieb Kier Borromeo [email protected] :

Ich war nicht sofort überzeugt. Ich muss über die Idee nachdenken.


Antworten Sie direkt auf diese E-Mail oder zeigen Sie sie auf GitHub an
https://github.com/gaearon/redux/issues/384#issuecomment -126977702.

Wout.
(auf dem Handy getippt, Entschuldigung der Knappheit)

Ich denke, dass der ActionCreator die Pflicht hat zu prüfen, ob eine Aktion ist
möglich (über einen Thunk), bevor Sie es blind aussenden.

Minderer haben die Verpflichtung, den zurückgegebenen Zustand stets gültig zu halten.

Das Aktionsprotokoll ist die Wahrheit dessen, was passiert ist, und der Zustand ist nur ein
Spiegelbild davon.

Am So, 2. August 2015, 07:07 Wout Mertens wout. [email protected] schrieb:

Tatsächlich wäre der vollständige Name in diesem Fall COUNT_INCREASE_REQUESTED,
die zwar etwas lang ist, aber immer noch die eigentliche Absicht vermittelt.

COUNT_INC_REQD?

Am Sonntag, 2. August 2015, 04:12 Uhr schrieb Kier Borromeo [email protected] :

Ich war nicht sofort überzeugt. Ich muss über die Idee nachdenken.


Antworten Sie direkt auf diese E-Mail oder zeigen Sie sie auf GitHub an
https://github.com/gaearon/redux/issues/384#issuecomment -126977702.

Wout.
(auf dem Handy getippt, Entschuldigung der Knappheit)

Wout.
(auf dem Handy getippt, Entschuldigung der Knappheit)

COUNT_INCREASED :-1: aus den bereits im Thread genannten Gründen
COUNT_INCREASE_REQUESTED :+1: aber wahrscheinlich zu ausführlich

Wie wäre es mit einer Empfehlung, Aktionstypen in der "Imperativ-Stimmung" zu schreiben (wie der berühmte Chris Beams' Git Commit Message Style Guide ). In diesem Fall funktioniert INCREASE_COUNT gut, weil es in der Imperativstimmung ist, dh "geschrieben, als ob es einen Befehl oder eine Anweisung gibt", und vermittelt die Vorstellung, dass das Erschaffen einer Handlung nur einen Wunsch oder eine Absicht bedeutet, dass etwas passieren sollte zu einem Zeitpunkt.

Ich neige dazu, ActionTypes als Dinge zu sehen, die auch in der Vergangenheit passiert sind. Ich fand Flux am Anfang einfacher zu grok, indem ich es mit ddd/cqrs/es verglich, mit dem ich bereits etwas vertraut war. Diese Diskussion zwischen @abdullin und @fisherwebdev könnte hier von Interesse sein. Besonders das Bit mit dem Titel "Aktionen -> Ereignisse"

Persönlich komme ich zu dem Schluss, dass wir zwei Entwurfsmuster und zwei Modelle vermischen, wie man über ein System nachdenkt. Beide sind getrennt gültig und können in einigen Anwendungen wahrscheinlich gemischt werden.

Der eine basiert auf EventSourcing, wobei das Action-Objekt repräsentiert, was passiert ist. Reduzierer interpretieren die Vergangenheit dann in einen Zustand, verschiedene Reduzierer können sie in unterschiedliche Ansichten der Vergangenheit interpretieren.

Die zweite basiert auf write ahead log (WAL) . Es wird verwendet, um alle Arten von harten Problemen zu lösen, beginnend mit der Wiederherstellung eines Dateisystems aus dem Journal, Datenbanktransaktionen, Replikation, Wiederherstellung auf einem anderen Computer nach einem Ausfall... Auch bekannt als Journal, Transaktionsprotokoll, Befehlsprotokoll...
In diesem Fall stellen Aktionsobjekte hauptsächlich die Absicht dar, den Zustand zu ändern, und was auch immer erforderlich ist, zB TRANSACTION_BEGIN, TRANSACTION_COMMIT... WAL wird in Datenbanken häufig verwendet, um den Zustand zu ändern. Auf dieser Basis werden alle möglichen verteilten Probleme gelöst.

Ich denke, dass Vanilla Flux eher wie WAL war. Ich denke, dass beides gültige Ansätze sind und es könnte nur von der Art der Anwendung abhängen, welcher Ansatz sinnvoller ist. Möglicherweise sollte Redux ihnen gegenüber agnostisch bleiben.

Mein Problem mit der Vergangenheitsform ist, dass es manchmal schwierig ist, Aktionsobjekte in der Vergangenheitsform zu benennen. Mein Problem mit der imperativen Stimmung ist, dass sie an das WAL-Designmuster gebunden ist. Daher untersuche ich derzeit eine Option, um meine Aktionsobjekte mit Substantiven zu beschreiben. Sie scheinen für beide Designmuster zu funktionieren und erlauben knifflige Namen. Sie sind ähnlich, manchmal identisch mit der zwingenden Stimmung, INCREASE_COUNT ändert sich in COUNT_INCREASE, VISIT ist VISIT usw.

Als Beispiel können wir DOM-Ereignisse nehmen. Versuchen Sie, 'mousemove', 'mouseup', 'mousedown' in der Vergangenheitsform zu benennen. Ich denke, es wird nicht lange dauern, die gleichen kniffligen Aktionen in Ihrer Domain zu finden. Es erlaubt 'Kontextmenü' und so.

Redux kann einfach alle Ansätze mit ihren Vor- und Nachteilen beschreiben und dem Entwickler die Wahl lassen, welches Modell zu seiner App passt und besser denkt. Ich glaube, dass Redux agnostisch sein und beides problemlos unterstützen kann.

Vielleicht sind beide für beide Entwurfsmuster akzeptabel - COMMENT_DELETE oder COMMENT_DELETION, dh OBJECT_VERB oder OBJECT_NOUN, sofern OBJECT_VERB nicht als zwingende Stimmung verstanden wird, was nicht so viel im Vergleich zu DELETE_COMMENT ist.

Dies ist der Grund, warum es verwirrend sein kann, beide in Dokumenten zu haben (während die Trennung technisch korrekt ist):

_Die einzige Möglichkeit, den Zustand zu verändern, besteht darin, eine Aktion auszusenden, ein Objekt, das beschreibt, was passiert ist. (Drei Prinzipien)_

_Eine Aktion ist ein einfaches Objekt, das eine Absicht darstellt, den Zustand zu ändern. (Aktion im Glossar)_

@vladap Das sehe ich wohl genauso.
Ich denke, es wurde offensichtlich, dass die Definition der Aktion selbst unzureichend genug war, um viel Verwirrung zu stiften. Dafür fehlt uns jetzt die Semantik.
Aktion - Aufruf, etwas zu tun oder die Tatsache, dass etwas passiert ist?
Die Antwort auf diese Frage definiert, wie intelligent Reduzierer sein sollte. Dies prägt die gesamte App.
Ich denke, dass es eine allgemeine Übereinstimmung gibt, dass Reduzierstücke Dumping sein sollten. Es ist der Kern von Redux, der einfach, synchron und nachladbar sein sollte. Um Dump-Reduzierer zu bekommen, sollten wir ihnen Aktionen wie "Aufruf, etwas zu tun" und nicht "Tatsache" propagieren. Da Fakten unterschiedlich interpretiert werden können, neigt Reducer dazu, einige Interpretationen vorzunehmen, die es automatisch intelligenter machen. Ich nenne lieber "Aufruf, etwas zu tun" - Anweisung (langer Name, der schlecht ist, aber ich mag Semantik).
Ich denke, dass es eine Kluft zwischen Anweisung und Tatsache als Werten gibt, aber wir nennen sie jetzt beides Handeln - dies ist die Hauptursache für Verwirrung.
Wie @gaearon das kommentiert hat
"Es gibt "intelligente" Aktionen, die irgendwann zu "dummen" Aktionen werden. Sie beschreiben oft, "was passieren sollte" Middleware interpretiert intelligente Aktionen und macht sie zu dummen."
Die Vergangenheitsform neigt dazu, dass eine Handlung eine Tatsache ist, also denke ich, dass dies eigentlich eine schlechte Idee ist. Ich glaube, dass Reduzierer Anweisungen erhalten sollte. Eine andere Sache, die ich erwähnen möchte, ist, dass dies alles mit der anderen Frage verbunden ist: "Wo soll die Geschäftslogik in meiner App leben?". Benutzer klickt irgendwo ( Tatsache ) was als Array von Anweisungen interpretiert wird . (fact)=>(List[instructions]) - genau das macht actionCreator jetzt. Und mir ist nicht klar, wie Middleware mit actionCreator korreliert. Ich denke, Middleware ist eher niedrig und sollte keine Entscheidungen treffen. Nur ein paar isomorphe Sachen wie Unboxing-Versprechen und -Thunks. PS Vielleicht ist die Absicht besser, da sie kürzer ist, wie @ioss sagte, aber auch hier ist die Anweisung in der Semantik besser.

Ich mag die Idee, Nomen zu verwenden! Das macht sie – abgesehen von der einfachen Benennung – zeitlos, sie sind Tatsache und Absicht/Anleitung zugleich.

Reduzierer mögen zwar ziemlich dumm sein, aber meiner Meinung nach könnten sie dennoch Geschäftslogik enthalten, wie: "Anzahl sollte niemals negativ werden".
Wenn sie völlig dumm waren, sollten sie entfernt und durch eine generische ersetzt werden.

Dies ist zwar eine ziemlich akademische Diskussion, solange wir keinen Aktionstyp-ist-ein-Substantiv-Validator haben ;) +1 für Substantive

Couter Beispiel ist es zu einfach und repräsentiert diesen Anwendungsfall nicht. Bedenken Sie, dass wir einige Datenbanken synchronisieren. Und wir möchten den Fortschrittsbalken dieses Prozesses anzeigen.

export function syncDb() {
    return (dispatch, getState) => {
        const {db:{client}} = getState().toJS();

        dispatch(createAction(STATUS_SYNC_DB)('syncing'));
        client.sync((progress)=> {
            dispatch(createAction(PROGRESS_SYNC_DB)(progress))
        }).then(()=> {
            dispatch(createAction(STATUS_SYNC_DB)('complete'));
        })
    };

Der Code ist nicht vollständig, aber er zeigt die Idee. Da wir async haben, ist es sogar unmöglich, dies im Reducer zu tun, daher ist es erzwungen, hier einen Dump zu erstellen, aber der Benutzer könnte versucht sein, in anderen Fällen eine Aktion wie SYNC_STARTED auszuführen und eine Geschäftslogik in den Reducer zu schreiben.
Reduzierer sind Dumps, aber wir brauchen sie immer noch und können sie für die Synchronisierung mit einer anderen Quelle wiederverwenden, weil sie Dumps sind.

INIT_DB: (state, action) => state.merge(action.payload),
PROGRESS_SYNC_DB: (state, action) => state.set('dbSyncProgress', action.payload),
STATUS_SYNC_DB: (state, action) => state.set('dbSyncMode', action.payload)

Ich verwende immutablejs, aber einige andere bevorzugen möglicherweise einfaches js und entfernen alle unveränderlichen js von Reduzierern, und die App würde immer noch funktionieren. Und es ist einfach zu bewerkstelligen, da sich die gesamte Geschäftslogik im Aktionsersteller befindet. @ioss das meine ich mit Dump Reducer. Es gibt also eine Trennung der Anliegen.

Eine weitere Sache ist, dass es großartig wäre, sowohl Anweisungen als auch Fakten zu versenden. Aber Tatsachen sollten so versandt werden, dass sie der Ausführung von Aktionserstellern vorausgingen, da dies die Erstellung von Tests für Aktionsersteller ermöglicht, die meiner Meinung nach der interessanteste Teil zum Testen sind.

@lapanoid : Ich bin gegen die total dummen Reduzierer.
Ihre Reduzierstücke sind ein gutes Beispiel dafür, dass sie so dumm sind, dass sie durch etwas ersetzt werden könnten wie:
(state, action) => state.set(action.type, action.payload)

Das bedeutet: Wenn die action.payload nie von den Reducern verarbeitet oder entschieden wird (weil sie keine Geschäftslogik haben sollten), können die Action-Ersteller auch einfach zusammenfügbare Payloads übergeben und werden so zu einer Art eigener Reducer und zum "echten" Reduzierstücke konnten entfernt werden.

Auch wenn sie so dumm sind, warum dann Hotreloading für Reduzierstücke? Sie würden sich kaum ändern.
Das Demonstrationsvideo von dan zeigt ziemlich dumme Reduzierer, trotzdem ändert er die Höhe des Inkrements, wodurch sie "Geschäftslogik" enthalten, an einer Stelle, an der sie meiner Meinung nach sein sollte.

Dies sind unterschiedliche Anwendungsfälle.

Für einen Zustand, der auf dem Server "lebt", sind Reduzierer dumm, weil es wenig Geschäftslogik gibt. Tatsächlich ist es sinnvoll, Reducer aus einem Schema zu generieren.

Für Zustände, die auf dem Client "leben" (zB komplexer Post-Editor), wird die Geschäftslogik in Reducern beschrieben.

@lapanoid Im Vergleich zu meinem Verständnis denke ich, dass Sie die Fakten um eine Ebene nach oben in Richtung eines Benutzers verschoben haben.

Dispatch(createAction(STATUS_SYNC_DB)('syncing'));
Dispatch(createAction(PROGRESS_SYNC_DB)(Fortschritt))
Dispatch(createAction(STATUS_SYNC_DB)('complete'));

Dies sind Tatsachen (Aktionen als Objekt), die in Ihrer AC-Logik passiert sind. Facts beschreiben die Ausführung einer Logik in AC.

Der Benutzer klickt irgendwo ("Tatsache"), was als Array von "Anweisungen" interpretiert wird. (fact)=>(List) - das ist es, was actionCreator jetzt tatsächlich macht.

Wenn der Benutzer klickt, ist dies standardmäßig noch kein Fakt. Wenn er klickt, führt er eine Aktion als Funktion (ActionCreator) und eine Logik aus, die zu Fakten führt (Aktionen als Objekt). Normalerweise werden synchrone Operationen 1:1 in Aktionen als Fakten übersetzt und die gesamte Logik wird in einem Reducer ausgeführt. Async zerstört dies und zwingt uns, den gesamten asynchronen Code mit all seinen Abhängigkeiten auf ActionCreators zu verschieben, was zu einer künstlichen Trennung der Geschäftslogik führen kann, insbesondere in Fällen, in denen die Logik zwischen Action-Ersteller und einem Reducer hin und her bewegt werden muss.

Auf Fakten basierende Reduzierungen sind lose Modelle. Reduzierer können alles tun, was auf der Grundlage von Fakten sinnvoll ist. Sie können schlau sein, sie können dumm sein (nur AC-Ergebnisse auf Zustand reduzieren).

Sie können Handlung als Objekt verwenden, um Anweisungen zu beschreiben, aber es ist das andere Denkmodell, das stärker gekoppelt ist (aber bevorzugt werden kann).

Mir wäre es gut, AKTION ALS FUNKTION (ActionCreator) und AKTION ALS OBJEKT zu haben.

@gaearon : zugestimmt. Ich meinte nicht, dass es keinen Platz für dumme Reduzierer gibt, nur dass ich nicht sehe, dass alles logisch sein sollte.

Meine Aktionsobjekte (Fakten) sind arrogant, sie haben keine Absichten, sie sagen nur - "das wurde getan" und du, lieber Reduzierer, machst dein Geschäft. Es ist mir egal. Ich werde Ihnen nicht sagen, was Sie tun sollen, es ist Ihre Sache. Meine Aktionsobjekte könnten sich darum kümmern, wenn Reducer freundlicherweise darum bittet, das Geschehene besser zu beschreiben, aber im Allgemeinen zögert er, Änderungen vorzunehmen (um die vorhandene Art von API zu erhalten).

Mit 100 Reduzierern kann es jedoch schwieriger sein, alles zu finden, was bei einem bestimmten Fakt passiert. Dies ist bei allen ereignisgesteuerten Programmierungen und stark getrennten Architekturen der Fall.

@vladap

Wenn er klickt, führt er eine Aktion als Funktion (ActionCreator) und eine Logik aus, die zu Fakten führt > (Aktionen als Objekt).

Dies ist ein aktuelles Design, aber ich denke, es ist tatsächlich falsch. Wenn die Benutzeriteration standardmäßig etwas Unveränderliches generiert und nur dann AC ausgelöst wird, können wir die AC-Ausführung testen. Dies könnte im Kern transparent erfolgen, denke ich, es wäre brutal, den Benutzer dazu zu bringen, zusätzliche Aktionen bei jedem AC durchzuführen.
In der realen Welt passierte beim Klicken des Benutzers - Puff - Tatsache. Auch wenn Redux das nicht denkt.

Meine Aktionsobjekte könnten sich interessieren, wenn Reducer freundlicherweise um eine bessere Beschreibung bittet

Wie kann es gemacht werden?

@ioss

Auch wenn sie so dumm sind, warum dann Hotreloading für Reduzierstücke?

AC ist auch heiß umgebaut - das ist also kein Argument

dennoch ändert er die Höhe des Inkrements, wodurch sie "Geschäftslogik" enthalten, an einer Stelle, an der sie meiner Meinung nach sein sollte.

sie erhalten INCREMENT_COUNTER, sie treffen keine Entscheidungen, sondern führen nur Operationen durch. Hier gibt es also keine Geschäftslogik. Sie sind Dump, aber Sie brauchen sie auch in einem so einfachen Fall. Sie wissen, wie man den Zustand von Aktionen aufrechterhält.

Ich denke, das Problem ist das Wort "Action" (in Action und ActionCreator, und ACs werden oft als DomEvent-Handler verwendet).
Wenn ich Action lese, verbindet mein Verstand sie mit den Ereignissen in der Ansicht (oder anderen Ereignissen, wie aus einem Backend) und ich habe immer den Gedanken, einen Schritt zurückzutreten. Ich muss mich wohl nur daran gewöhnen, um es in mein Unterbewusstsein zu bekommen. :)

Momentan überlege ich: DomEvent -> ViewActionCreator ("linker" Teil von ActionCreator mit VL) -> ViewAction/ExternalAction -> (optional) Middleware/Store mit ViewActionHandler ("rechter" Teil von ActionCreator mit BL und möglichen Nebenwirkungen ) -> (Store)Action -> Reduzierer.
Auf diese Weise ist es möglicherweise möglich, ViewActions mit ihrer StoreAction zu verbinden, was mir die Möglichkeit geben könnte, View/ExternalActions "visuell" im Devtool wiederzugeben, aber StoreActions auf den Zustand anzuwenden, ohne Nebeneffekte zu wiederholen.
Keine Ahnung, nur eine Idee...

Die Sache ist, dass die Geschäftslogik (BL) im Allgemeinen nicht synchron ist, daher ist AC sowieso der bessere Ort dafür. BL manchmal in AC und manchmal in Reduzierer zu setzen ist verwirrend (vielleicht ist es nur für mich verwirrend, aber trotzdem =))

In Bezug auf den Benennungsstil von Ereignissen funktioniert meiner Meinung nach die Vergangenheitsform am besten für die Art von Zwischenereignissen von ChildView zu ParentView, die Sie oft schreiben, wenn Sie Backbone-Apps erstellen, z. B. CLOSE_BUTTON_CLICKED oder DROPDOWN_CHANGED . Ein Controller einer Art könnte dann diese Ereignisse von den Details der UI-Implementierung abstrahieren und sie als allgemeinere/wiederverwendbare App-Domänenereignisse (oder Befehle) in der zwingenden Stimmung wie CLOSE_MODAL oder SET_SELECTED_ITEM erneut versenden.

Abgesehen davon lässt diese Umwandlung von DOM-Ereignissen in App-Domänenaktionen, die häufig bei einem Klick oder einem Änderungshandler auftreten, implizit eine gewisse Geschäftslogik in die Ansichtsschicht imo durch. Ich bin mir nicht sicher, was ich davon halte, aber solange es sich natürlich auf intelligente / verbundene Komponenten beschränkt, scheint es in Ordnung zu sein, da sie sowieso viel enger an die Zustandsschicht gekoppelt sind.

Wir wissen, dass eine Aktion, sobald sie auf die Oberfläche des Reduzierstücks trifft, dumm sein muss, nur von einem Typ und einer optionalen Nutzlast beeinträchtigt sein muss. Ich bin mit Aktionserstellern und Middleware, die Geschäftslogik enthalten, vertraut, aber es scheint hilfreich zu sein, festzulegen, dass sich eine solche Geschäftslogik ausschließlich auf die Umwandlung einer intelligenten Aktion in eine dumme Aktion bezieht, sonst nichts. Andere Geschäftslogik würde höchstwahrscheinlich auf dem Server oder alternativ auf dem Reducer stattfinden.

Fwiw Ich würde eine Umbenennung von Aktionen in Befehle unterstützen, da es konzeptionell ziemlich gut zum Befehlsmuster passt. Für mich erweckt eine Aktion den Eindruck, dass das _wie_ der Operation bereits vorherbestimmt ist, was nicht wirklich gut mit der Kerngeschäftslogik an anderer Stelle (Server oder Reducer) zusammenpasst. In Redux haben wir in Wirklichkeit nur ein DOM-Ereignis in einen der verfügbaren App-Domain-Befehlstypen umgewandelt, mit allen notwendigen Daten versorgt und vergessen ... das heißt, wir geben einen Befehl aus.

Wenn etwas als "Aktion" bezeichnet werden sollte, wäre es die Beschreibung des Ereignisses, das stattfindet, wenn ein dummer Befehl zu einem bestimmten Zeitpunkt auf den Reduzierer trifft. Es sind also _Aktionen_, die wir während einer Zeitreise wiederholen, nicht Befehle und ihre möglichen Nebenwirkungen. Der Reducer _handelt_ auf einen Befehl und führt somit eine konkrete _Aktion_ aus, aber dies wäre eine interne Implementierungsterminologie, die von Bibliotheksbenutzern abstrahiert wird, die sich nur um die Ausgabe von Befehlen kümmern müssen ... dh beabsichtigt, dass etwas passieren _soll_.

Aus Wikipedia zum Befehlsmuster:

Das Befehlsmuster ist ein Verhaltensentwurfsmuster, bei dem ein Objekt verwendet wird, um alle Informationen zu kapseln, die zum Ausführen einer Aktion oder zum Auslösen eines Ereignisses zu einem späteren Zeitpunkt erforderlich sind.

Wie auch immer, es tut mir leid, wenn die Umbenennung in Befehle zuvor diskutiert und dagegen entschieden wurde, können Sie sie einfach ignorieren. Es tut mir auch leid, wenn ich dieses Thema vom Thema abschweife, zögern Sie nicht, mich in die richtige Richtung zu weisen. Nur meine 2 Cent wert :-)

Meine Aktionsobjekte könnten sich interessieren, wenn Reducer freundlicherweise um eine bessere Beschreibung bittet
Wie kann es gemacht werden?

Es war nur eine Metapher:) Der Versuch zu vermitteln, dass Aktionsobjekte gut durchdacht sein sollten, da es schwierig sein kann, sie einmal zu ändern, und einige Reduzierer sind bereits daran gebunden.

@jedrichards haha, jetzt haben wir Fakten, Aktionen, Anweisungen, Absichten und Befehle =) Es ist lustig, wie die Leute dasselbe anders sehen sollte als nächstes passieren und einige Informationen darüber in sich tragen. Und BUTTON_CLICKED tut dies tatsächlich nicht, also ist es Dumper. Eine Tatsache interpretiert eine Reihe von Anweisungen, die Sie vielleicht sagen.

Der Versuch zu vermitteln, dass Aktionsobjekte gut durchdacht sein sollten, da es schwierig sein kann, sie einmal zu ändern, und einige Reduzierer sind bereits damit verbunden.

Ja. Aus diesem Grund möchte ich etwas Klarheit bei Aktionen haben, deren Herangehensweise wirklich Einfluss auf die gesamte App hat.

Die Sache ist, dass die Geschäftslogik (BL) im Allgemeinen nicht synchron ist, daher ist AC sowieso der bessere Ort dafür. BL manchmal in AC und manchmal in Reduzierer zu setzen ist verwirrend (vielleicht ist es nur für mich verwirrend, aber trotzdem =))

Dies ist der Preis, der derzeit für das Schreiben von Hot-Reload-Code gezahlt wird.

AC ist auch heiß umgebaut - das ist also kein Argument

Wenn sie asynchronen Code enthalten, können sie nicht im laufenden Betrieb wiedergegeben werden, und Sie können dies nicht deterministisch tun. Redux DevTools ignorieren sie bei der Wiedergabe und die Wiedergabe arbeitet mit Ergebnissen von asynchronem AC - nur für Aktionsobjekte => Hot-Replay-Code ist nur in Reduzierern enthalten.

@vladap Das macht Sinn, ich wusste nicht, dass sich DevTools so verhalten, danke. Sie sind also nur bei Synchronisierung wiederholbar? Dann können wir BL immer in AC finden und versuchen, sie so synchron wie möglich zu machen

Sie sind also nur bei Synchronisierung wiederholbar?

Ja, der Standard-CombineReducers unterstützt nur Synchronisierungscode. Sie könnten Ihre eigenen CombineReducer schreiben und asynchronen Code deterministisch ausführen, aber da sich alle Reducer bis zur Ausführung der nächsten Aktion synchronisieren müssten, ist der Nettogewinn fraglich - Aktionsverarbeitung und Rendering sind gekoppelt (im Gegensatz zu z Seien Sie schnell, um eine nicht reagierende Benutzeroberfläche zu vermeiden.

Mehr Code, den Sie in AC stecken, weniger Code, den Sie wiedergeben/zeitreisen und live bearbeiten können, würden Sie mit einem einfachen Debug-Log enden - in einem solchen Fall könnten Sie wahrscheinlich einfach direkt mutieren und anstelle von Aktionen console.log() verwenden. Wenn Sie den AC-Code ändern und auf gespeicherte Aktionen anwenden, sehen Sie keine Auswirkung Ihrer Änderung. Wenn Sie den Reduziercode ändern, werden Ihre gespeicherten Aktionen anders wiedergegeben -> Sie können in der Zeit zurückgehen, den Code ändern und die Zeit vorwärts verschieben, um zu sehen, wie es gilt.

@vladap, was sind Beispiele für die Art von Nebenwirkungen, die Sie wiederholen möchten?

Bei einer zustandslosen Ansichtsebene kann ich nur an die Netzwerkinteraktion denken, und
das erscheint mir nicht ganz ungefährlich...

Ich stimme dem zu, was Sie zuvor geschrieben haben, wenn sie Befehle an den Server senden
stimmen nicht mit den Tatsachen überein, die wir an das Reduzierstück senden, aber wir führen sie zusammen.
Gute Umsetzung für #313!

Am Mo, 3. August 2015, 22:11 Uhr schrieb vladap [email protected] :

Sie sind also nur bei Synchronisierung wiederholbar?

Ja, der Standard-CombineReducers unterstützt nur Synchronisierungscode. Du könntest deine schreiben
eigene combineReducers und führe asynchronen Code deterministisch aus, aber
weil sich alle Reduzierer synchronisieren müssten, bis die nächste Aktion ausgeführt wird
der Nettogewinn ist fraglich - Aktionsverarbeitung und Rendering sind gekoppelt
(im Gegensatz zu z. B. in Game-Engines) daher muss die Ausführung von Reduzierern schnell sein
um eine nicht reagierende Benutzeroberfläche zu vermeiden.

Mehr Code, den Sie in AC eingeben, weniger Code, den Sie wiedergeben/zeitreisen und bearbeiten können
live würden Sie mit einem einfachen Debug-Protokoll enden - in einem solchen Fall könnten Sie
wahrscheinlich einfach direkt mutieren und anstelle von Aktionen console.log() verwenden. Wenn
Sie ändern den AC-Code und wenden ihn auf gespeicherte Aktionen an, von denen Sie keine Auswirkungen sehen werden
dein Wechselgeld. Wenn Sie den Reduziercode ändern, werden Ihre gespeicherten Aktionen wiederholt
anders -> Sie können die Zeit zurückdrehen, den Code ändern und die Zeit vorwärts verschieben
um zu sehen, wie es gilt.


Antworten Sie direkt auf diese E-Mail oder zeigen Sie sie auf GitHub an
https://github.com/gaearon/redux/issues/384#issuecomment -127393209.

Wout.
(auf dem Handy getippt, Entschuldigung der Knappheit)

@wmertens Ich wollte Nebenwirkungen nicht wiederholen, es wird in # 307 besprochen.

@jedrichards Befehlsmuster definiert explizit, welcher Befehl ausgeführt werden soll, mit anderen Worten, welches genaue Verhalten ausgeführt werden soll. Es ist ein 1:1-Verhältnis. Fluss hat im Allgemeinen eine 1:M (viele) Beziehung zwischen Aktion und ausgeführtem Verhalten. Muster mit 1:M-Beziehung wird meines Wissens als Beobachtermuster bezeichnet.

Das Umbenennen von Aktionen in Befehle würde nicht dazu beitragen, die Grundursache der Verwirrung zu lösen (das sind die verwendeten Begriffe im Vergleich zu den standardmäßig vorgeschlagenen Entwurfsmustern). In einigen Befehlsmusterimplementierungen werden Aktionen anstelle von Befehlen verwendet. In unserem Kontext sind sie praktisch dasselbe.

Wenn mir gesagt wird, dass es das Befehlsmuster ist, erwarte ich, dass eine Seite definiert, was ausgeführt werden soll, und geben Sie es der anderen Seite, die es blind ausführt. Wenn der Befehl turnOnRadio definiert ist, wäre es seltsam, das Licht einzuschalten.

Der ursprüngliche Flux ist entweder ein überladenes Befehlsmuster, bei dem Aktionsobjekte mehr und möglicherweise nicht verwandte Verhaltensweisen auslösen können, was verwirrend sein kann.

Oder es handelt sich um ein überladenes Befehlsmuster, bei dem die Ausführung eines einzelnen Verhaltens auf mehrere Geschäfte verteilt werden kann. Um also ein Radio einzuschalten, muss ein Geschäft es einstecken, während das andere Geschäft wartet, bis es angeschlossen ist, und es dann einschalten.

Oder es ist ein Observer-Muster mit Ereignissen, die seltsamerweise als Aktionsobjekte bezeichnet werden, was verwirrend ist. Dann erwarte ich, dass eine Seite nur signalisiert, dass etwas passiert ist, ohne zu wissen, was als nächstes passieren wird. Wenn eine Seite signalisiert, dass das Radio eingeschaltet ist, kann die andere Seite auf Wunsch das Licht einschalten.

In allen Fällen kann es bedeuten, dass bereits eine Logik ausgeführt wurde, die entweder zu Befehlen oder Ereignissen geführt hat. Befehle vs. Ereignisse definieren nur den Grad der Kopplung.

@wmertens Ich wollte Nebenwirkungen nicht wiederholen, es wird in # 307 besprochen.

Aber ja, es wäre unrein, Versprechen im Reducer zu verwenden, was bedeutet, dass ich tatsächlich Nebenwirkungen wiedergeben würde.

@vladap könntest du deinen letzten Satz

@ioss : Vergiss es, es ist falsch. Ich denke, es geht nicht nur mit CombineReducers.

Wie vladap erwähnt, ist es im Moment nicht konsistent. Dies sollte behoben werden, siehe:

Die einzige Möglichkeit, den Zustand zu verändern, besteht darin, eine Aktion auszusenden, ein Objekt, das beschreibt, was passiert ist. (Drei Prinzipien, Reduzierer)
Eine Aktion ist ein einfaches Objekt, das eine Absicht darstellt, den Zustand zu ändern. (Aktion im Glossar)

Ein Vorschlag:

Aktionen: Wie einige Leute erwähnt haben, wird eine Aktion als die Aussage einer _Absicht_ gesehen, etwas zu tun. Derzeit geben Aktionsersteller _Intents_ Absichten eines Benutzers zurück, aber irgendwie werden diese _Intents_ später als Tatsachen angesehen.

Ereignisse: Im Event Sourcing werden Ereignisse als Tatsachen betrachtet, die in der Vergangenheit stattgefunden haben. Es gibt bereits ein Konzept für einen Ereignisspeicher (_nicht_ einen Aktionsspeicher).

Events statt Aktionen
Ich denke, dass Action-Ersteller Ereignisse zurückgeben sollten. Eigentlich sind Action-Schöpfer schon die _Intents_. Durch den Aufruf einer Aktion Schöpfer Funktion, wird die Aktion ausgeführt. Während eine Aktion ausgeführt wird, können Ereignisse ausgelöst werden, entweder durch Zurückgeben oder durch Zurückgeben einer Rückruffunktion.

Es ist nur eine einfache Umbenennung, aber ich denke, es würde helfen. Was denken Sie?

Sie könnten Ihre eigenen CombineReducer schreiben und asynchronen Code deterministisch ausführen, aber da sich alle Reducer bis zur Ausführung der nächsten Aktion synchronisieren müssten, ist der Nettogewinn fraglich - Aktionsverarbeitung und Rendering sind gekoppelt (im Gegensatz zu z Seien Sie schnell, um eine nicht reagierende Benutzeroberfläche zu vermeiden.

Auch diese meine Aussage macht keinen Sinn. Andere Aktionen würden noch durchgeführt. Ich bin mir nicht sicher, warum ich dachte, dass es eine Art Lock-Step wie in Spielen gibt. Es ist gut zu wissen, dass die mehrfache Ausführung von Aktionserstellern, die dieselben Aktionen ausführen, möglicherweise zu Race-Bedingungen und unvorhersehbaren Zuständen führen kann.

Ich denke, dies sollte aus denselben Gründen wie https://github.com/gaearon/redux/issues/377#issuecomment -127703551 geschlossen werden @gaearon. (allerdings war diese Diskussion zumindest für mich ziemlich aufschlussreich)

Nun, ich denke, dass es etwas ganz anderes ist, einfach etwas in Dokumenten zu empfehlen
vom Refactoring der API.
Ich denke, wir haben einen Konsens erzielt, dass Aktionskonstanten in der am sinnvollsten sind
Vergangenheitsform, und dass Befehle zwingend sein können, aber umgewandelt werden müssen
zu Vergangenheitsform-Aktionen von Aktionserstellern oder Middleware.

Am Dienstag, den 4. August 2015, 21:25 Uhr schrieb Sergey Lapin [email protected] :

Ich denke, dies sollte ebenso geschlossen werden wie #377 (Kommentar)
https://github.com/gaearon/redux/issues/377#issuecomment -127703551 für
gleiche Gründe @gaearon https://github.com/gaearon. (aber das
Diskussion war zumindest für mich sehr aufschlussreich)


Antworten Sie direkt auf diese E-Mail oder zeigen Sie sie auf GitHub an
https://github.com/gaearon/redux/issues/384#issuecomment -127728289.

Wout.
(auf dem Handy getippt, Entschuldigung der Knappheit)

Letztendlich beginnen wir, dasselbe zu diskutieren – die Art der Handlungen, die in Ordnung ist, weil alles miteinander verbunden ist. Und ich sehe hier keinen Konsens. Wenn eine Handlung Absicht ist, sollte sie keine Vergangenheitsform sein, und wenn es eine Tatsache ist, sollte sie es sein. Aber es würde keine Umbenennung aus Gründen aus #377 geben

Aktion wird jetzt tatsächlich auf beide Arten verwendet, weil es beides sein kann. Wie das Photon sowohl Welle als auch Teilchen ist, hängt es von der Perspektive ab.

ja, aber bis es den Laden erreicht, sind die Absichten zusammengebrochen
Fakten :-)

Am Mittwoch, 5. August 2015, 10:25 Uhr schrieb Sergey Lapin [email protected] :

Actioin wird jetzt tatsächlich auf beide Arten verwendet, weil beides sein kann. Wie Photon ist
Sowohl Welle als auch Teilchen hängt von der Perspektive ab.


Antworten Sie direkt auf diese E-Mail oder zeigen Sie sie auf GitHub an
https://github.com/gaearon/redux/issues/384#issuecomment -127912543.

Wout.
(auf dem Handy getippt, Entschuldigung der Knappheit)

Ich glaube definitiv nicht.

Ich denke, dass Absichten im Allgemeinen als Absichten des Benutzers verstanden werden, sie repräsentieren die Interaktion des Benutzers mit der Benutzeroberfläche. Absichten werden dann entweder in Ereignisse/Fakten oder Aktionen/Befehle übersetzt, je nachdem, auf welchem ​​Muster Sie Ihr System aufbauen möchten. Ich würde es eher vermeiden, den Intent-Begriff in einem anderen Kontext zu verwenden.

Die Benutzerabsicht kann showMeTop10Todos sein, die in TODOS_LOAD_BEGIN und TODOS_LOAD_SUCCESS/FAILURE übersetzt wird. Der Benutzer kümmert sich nicht um sie, es handelt sich um interne Ereignisse/Fakten oder Aktionen/Befehle. Der Benutzer hat Absichten und kümmert sich im Allgemeinen um angezeigte Ergebnisse, es ist ihm egal, was dazwischen getan werden muss.

Wie @adri erwähnt, ist der gebräuchliche Begriff im EventSourcing Event oder DomainEvent. Ereignis ist auch der gebräuchliche Begriff im Beobachtermuster, der angemessener ist, wenn man TODOS_LOAD_BEGIN und TODOS_LOAD_SUCCESS/FAILURE als das sieht, was passiert ist und wenn eine 1:M-Beziehung besteht.

Der Begriff FACT wird in der OLAP-Analyse verwendet, wo er für Faktentabellen in einem Sternschema zusammen mit Dimensionstabellen verwendet wird. Ich würde sagen, dass Fakt ein allgemeinerer Begriff ist, der alles repräsentiert, was analysiert wird, es kann ein Ereignis sein, Messungen .... Ich bin mir nicht bewusst, dass es direkt in einem Programmierentwurfsmuster verwendet wird, obwohl ich nicht alle kenne.

User Intents sind eine Ebene höher, würde ich sagen. Benutzerabsichten werden in React-Komponenten in ActionCreators umgewandelt. Wir können eine Benutzerabsicht nehmen, den aktuellen Redux.state und/oder den aktuellen lokalen Zustand, der in der React-Komponente gepflegt wird, nehmen und entscheiden, ob wir ActionCreator tatsächlich ausführen oder nicht.

Der Ablauf ist UserIntent (virtueller Begriff, dargestellt durch DOM-Ereignishandler) > ActionCreator > Action-Objekt.

Vielleicht sollte es in Dokumenten vier Prinzipien geben.

State is a result of an immutable past.

Dies ist kontrovers, wie diese Diskussion beweist. Wir werden in der Dokumentation kein bestimmtes Namensschema vorschreiben.

Wir haben jetzt auch die Terminologie eingefroren, also werden wir keine "Ereignisse", "Fakten" oder etwas anderes vorstellen.

Danke an alle fürs Mitmachen ;-). Schließung als nicht umsetzbar.

Ich stimme @lapanoid zu, dass es in diesem Thread sehr wenig Konsens gibt.
Eines der Dinge, die mir fehlen, sind Meinungen zum EventSourcing vs. WAL-Ansatz, siehe https://github.com/rackt/redux/issues/384#issuecomment -127163050 und https://github.com/rackt/redux/ Issues/384#issuecomment -127272825.

Soll eine intelligente Komponente CLOSE_BUTTON_CLICKED (EventSourcing, Observer Pattern) oder CLOSE_MODAL (Command Pattern) Aktionen auslösen?
(Ich spreche nicht von der Vergangenheitsform / naun / ... Formulierung)

Persönlich mag ich die Punkte von

Ich denke, es ist ganz klar: Es sind Dinge passiert (Beobachter
Muster: Benutzer hat auf den Like-Button geklickt, der Server hat eine neue Chat-Nachricht gesendet) und
Dinge, die passieren sollen (Befehlsmuster: Benutzerdetails abrufen von
Server, Desktop-Benachrichtigung anzeigen) und sie reisen über denselben
Nachrichtenbus, der Dispatch-Aufruf.

Jedoch.

Die einzigen Dinge, die im Staat sinnvoll zu speichern sind, sind Beobachtungen,
da Befehle keinen direkten Einfluss auf den Zustand haben. Die gewünschte Änderung nicht
passieren, bis der Befehl die Reduzierstücke erreicht, und das Ergebnis von
der Befehl wird wahrscheinlich eine neue Beobachtung sein.

Der Befehl kann allenfalls zur Beobachtung führen, dass eine Anfrage gestellt wurde,
und ich glaube, es wäre am besten, dies explizit zu machen, indem man die
actioncreator oder Middleware, die den Befehls-Dispatch vermittelt, der
Überwachung.

Daher sollte jede Aktion, die zu den Reduzierern gelangt, in geschrieben werden
die Vergangenheitsform. Alles andere ist bestenfalls eine Abkürzung und schlimmstenfalls eine Quelle
der Verwirrung.

Am Mittwoch, 19. August 2015 um 18:25 Uhr Peter Uithoven [email protected]
schrieb:

Ich stimme @lapanoid https://github.com/lapanoid zu, dass es sehr
wenig Konsens in diesem Thread.
Eines der Dinge, die mir fehlen, sind Meinungen zum EventSourcing vs. WAL
Ansatz, siehe #384 (Kommentar)
https://github.com/rackt/redux/issues/384#issuecomment -127163050 und #384
(Kommentar)
https://github.com/rackt/redux/issues/384#issuecomment -127272825.

Sollte eine intelligente Komponente CLOSE_BUTTON_CLICKED (EventSourcing,
Beobachtermuster) oder CLOSE_MODAL (Befehlsmuster) Aktionen?
(Ich spreche nicht von der Vergangenheitsform / naun / ... Formulierung)

Persönlich mag ich @jedrichards https://github.com/jedrichards 's Punkte
dass intelligente Komponenten Ereignisse in generische/wiederverwendbare App-Domänen übersetzen können
Aktionen. Ich denke, das schafft eine bessere Trennung zwischen Benutzeroberfläche und Geschäft
Logik. Wenn es mehrere Ereignisse gibt, die zu den gleichen Aktionen führen, ist dies
begrenzt auch die Anzahl der Aktionen.


Antworten Sie direkt auf diese E-Mail oder zeigen Sie sie auf GitHub an
https://github.com/rackt/redux/issues/384#issuecomment -132680145.

Wout.
(auf dem Handy getippt, Entschuldigung der Knappheit)

Was die CLOSE_BUTTON_CLICKED vs CLOSE_MODAL betrifft, imho die eigentliche Aktion, die
gesendet werden soll, ist MODAL_GOT_HIDDEN oder einfach MODAL_HIDDEN, und die
actionCreator könnte hideModal() heißen.

Am Mi, 19. August 2015 um 23:32 Wout Mertens wout. [email protected]
schrieb:

Ich denke, es ist ganz klar: Es sind Dinge passiert (Beobachter
Muster: Benutzer hat auf den Like-Button geklickt, der Server hat eine neue Chat-Nachricht gesendet) und
Dinge, die passieren sollen (Befehlsmuster: Benutzerdetails abrufen von
Server, Desktop-Benachrichtigung anzeigen) und sie reisen über denselben
Nachrichtenbus, der Dispatch-Aufruf.

Jedoch.

Die einzigen Dinge, die im Staat sinnvoll zu speichern sind, sind Beobachtungen,
da Befehle keinen direkten Einfluss auf den Zustand haben. Die gewünschte Änderung nicht
passieren, bis der Befehl die Reduzierstücke erreicht, und das Ergebnis von
der Befehl wird wahrscheinlich eine neue Beobachtung sein.

Der Befehl kann höchstens zur Beobachtung führen, dass eine Anfrage
gemacht, und ich glaube, es wäre am besten, dies explizit zu machen, indem man die
actioncreator oder Middleware, die den Befehls-Dispatch vermittelt, der
Überwachung.

Daher sollte jede Aktion, die zu den Reduzierern gelangt, in geschrieben werden
die Vergangenheitsform. Alles andere ist bestenfalls eine Abkürzung und schlimmstenfalls eine Quelle
der Verwirrung.

Am Mittwoch, 19. August 2015 um 18:25 Uhr Peter Uithoven [email protected]
schrieb:

Ich stimme @lapanoid https://github.com/lapanoid zu, dass es sehr
wenig Konsens in diesem Thread.
Eines der Dinge, die mir fehlen, sind Meinungen zum EventSourcing vs. WAL
Ansatz, siehe #384 (Kommentar)
https://github.com/rackt/redux/issues/384#issuecomment -127163050 und #384
(Kommentar)
https://github.com/rackt/redux/issues/384#issuecomment -127272825.

Sollte eine intelligente Komponente CLOSE_BUTTON_CLICKED (EventSourcing,
Beobachtermuster) oder CLOSE_MODAL (Befehlsmuster) Aktionen?
(Ich spreche nicht von der Vergangenheitsform / naun / ... Formulierung)

Persönlich mag ich @jedrichards https://github.com/jedrichards 's Punkte
dass intelligente Komponenten Ereignisse in generische/wiederverwendbare App-Domänen übersetzen können
Aktionen. Ich denke, das schafft eine bessere Trennung zwischen Benutzeroberfläche und Geschäft
Logik. Wenn es mehrere Ereignisse gibt, die zu den gleichen Aktionen führen, ist dies
begrenzt auch die Anzahl der Aktionen.


Antworten Sie direkt auf diese E-Mail oder zeigen Sie sie auf GitHub an
https://github.com/rackt/redux/issues/384#issuecomment -132680145.

Wout.
(auf dem Handy getippt, Entschuldigung der Knappheit)

Wout.
(auf dem Handy getippt, Entschuldigung der Knappheit)

Was mich betrifft, ist die beste Idee dieses Threads Call-Action-Substantive ohne Zeitform wie ITEM_CREATION. Ich denke, die Anspannung selbst ist die Quelle der Verwirrung.

Ich denke, die Anspannung selbst ist die Quelle der Verwirrung.

Ich würde allgemeiner sagen, dass die Hauptursache für Verwirrung die Anwendung eines widersprüchlichen mentalen Modells ist.

Dies ist wirklich eine Frage der Perspektive; Ich kann leicht für die Vergangenheitsform argumentieren, weil das mentale Modell, das für mich am bequemsten ist, Event Sourcing ist, aber ich habe auch die Perspektive der anderen Vorschläge verstanden. Ich denke, wir sollten davon Abstand nehmen, auf eine feste Haltung zu drängen, weil wir verstehen müssen, dass Menschen mit unterschiedlichem Hintergrund von unterschiedlichen Erklärungen profitieren, die ihrem natürlichen mentalen Modell entsprechen. Einen Vorschlag einem anderen vorzuziehen macht es für manche schwieriger, wenn auch für andere einfacher. Dies "offiziell" in der Schwebe zu lassen, aber die Erklärung von Aktionen auf das spezifische Publikum eines Blog-Posts, Tweets oder Podcasts abzustimmen, wird jedem direkter dienen, denke ich.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen