Redux: Redux-Screencast-Serie auf Egghead

Erstellt am 24. Nov. 2015  ·  69Kommentare  ·  Quelle: reduxjs/redux

Wenn Sie Redux Repo verfolgen, sich aber noch nicht damit befasst haben oder einige seiner grundlegenden Aspekte verwirrt sind, werden Sie erfreut sein zu erfahren, dass Egghead gerade meine Serie Erste Schritte mit Redux veröffentlicht hat .

Es behandelt die gleichen Themen wie der "Basics"-Teil der Dokumentation, taucht aber hoffentlich ein wenig tiefer ein und stellt sicher, dass Sie die Redux-Grundlagen _wirklich_ verstehen.

Ich plane, mehr Inhalte über Redux auf Egghead zu erstellen – diesmal nur für Abonnenten. Es wird weiterführende Themen enthalten. Wenn Sie spezielle Vorschläge haben, lassen Sie es mich bitte in diesem Thread wissen!

feedback wanted

Hilfreichster Kommentar

@markerikson danke, dass du mich bei dieser Fragestellung unterstützt hast. Auch auf die Gefahr hin, als argumentativ zu wirken, möchte ich die Vorstellung, dass dies "App-Ebene" vs. "UI-Ebene" ist, ein wenig zurückdrängen.

Hinweis: Der Einfachheit halber verwende ich thunk , um einen abriträren Middleware-Ansatz für die Asynchronisierung darzustellen, egal ob es sich tatsächlich um Redux-Thunk oder Redux-Promise oder was auch immer handelt.

Ihre UI-Schicht verbindet nur Benutzerinteraktionen mit Handlern. Wenn jemand auf eine Schaltfläche klickt, ist Ihre Benutzeroberfläche so manipuliert, dass _some_ Handler aufgerufen wird. Oft erhält die Komponente diese Handler als Requisiten --- vielleicht zum Beispiel ein gebundener Aktionsersteller. Die Benutzeroberfläche ist sich nicht bewusst, was passiert, wenn sie einen Handler aufruft – sie ruft sie einfach auf.

Für die UI-Schicht macht es keinen Unterschied, ob der "Handler" eine Funktion absetzt (die von der Middleware verarbeitet wird) oder ob er einen asynchronen Aufruf ausführt und _dann_ eine einfache Aktion absetzt --- die UI ist völlig agnostisch (oder zumindest _kann_ agnostisch sein)

Ein großer Teil Ihrer "App" befindet sich in diesen "Handlern", unabhängig davon, ob Sie Thunks verwenden oder nicht. In einer typischen React-/Redux-App sind diese "Handler" oft eine Art Aktionsersteller. Sie könnten all Ihre asynchronen Sachen als Thunks schreiben und sie versenden. Oder Sie könnten all Ihre asynchronen Sachen als Funktionen schreiben, die dispatch als Argument akzeptieren. Aus der Sicht der Komponente ist es entweder someHandler(dispatch) ODER dispatch(someHandler()) , oder im Fall von Erstellern gebundener Aktionen, die von einer höheren Stelle weitergegeben wurden, sind es in beiden Fällen nur someHandler() . Sie könnten eine Version von bindActionCreators erstellen, die diesen Unterschied zur UI-Ebene vollständig maskieren würde.

Wenn Sie mir eine Reaction/Redux-Anwendung geben, die mit Action-Erstellern unter Verwendung von Redux-Thunk geschrieben wurde, könnte ich Redux-Thunk vollständig austauschen und einen Nicht-Middleware-Ansatz verwenden, ohne _grundsätzlich_ die UI-Schicht zu ändern. (Anmerkung: Ich beschönige, wo/wie Sie getState injizieren, aber ich _glaube_, dass das hier ein kleines Detail ist).

Daher kann ich nur schwer akzeptieren, dass die Unterscheidung zwischen "innen" und "außen" "App-Ebene" oder "UI-Ebene" ist.

Ich freue mich über die Diskussion und hoffe, dass ich nicht negativ rüberkomme.

Alle 69 Kommentare

:+1:

  1. Zustand der lokalen Komponente vs. globaler Zustand
  2. Aktion, die von mehreren Reduzierern verarbeitet wird, vs. 1-zu-1-Aktion-Reduzierer-Beziehung
  3. Umgang mit Aktionsketten (insbesondere asynchronen), wenn die zweite Aktion unmittelbar nach Beendigung der ersten ausgelöst werden soll.
  4. Optimierungstechniken, um unnötige Neuerneuerungen (Batching-Aktionen, Neuauswahl usw.) zu vermeiden.

:+1:

Ich habe mir gerade die ersten 16 Folgen der Serie angesehen und denke, dass sie eine ausgezeichnete Ressource sind, die wir wahrscheinlich für interne Schulungen in der Firma verwenden werden, für die ich arbeite. Die Tatsache, dass Sie jedoch für Ihren Zustandsbaum immer nur einfache Objekte und Tiefkühlung verwendet haben und niemals unveränderliche Bibliotheken wie immutable-js verwenden oder darauf verweisen, lässt mich fragen, ob Sie die Leute auf diesem Weg ermutigen oder ob dies nur Präsentationen macht die Ideen einfacher?

Wäre toll, eure Meinung dazu zu erfahren.

Das Einfügen von Immutable in die Mischung würde Anfänger verwirren, die lernen müssen, zwischen Redux und Immutable API zu unterscheiden, möglicherweise annehmen, dass Immutable erforderlich ist usw. Es ist jedoch eine gute Idee, ein paar fortgeschrittene Lektionen zu absolvieren!

Das Einfügen von Immutable in die Mischung würde Anfänger verwirren, die lernen müssen, zwischen Redux und Immutable API zu unterscheiden, möglicherweise annehmen, dass Immutable erforderlich ist usw. Es ist jedoch eine gute Idee, ein paar fortgeschrittene Lektionen zu absolvieren!

Okay, macht Sinn. Einfach gut zu wissen, was hinter dieser Entscheidung steckt :-).

Was @smashercosmo sagte :+1:

Unit-Tests. TDD.

Was @cateland sagte :+1:

Ich muss sagen, ich bin sehr beeindruckt von Ihren Fähigkeiten, mit denen Sie auf diese Weise hervorragende js-Bibliotheken mit umfangreicher Dokumentation und prägnanten Tutorials erstellen können.

Nachdem ich alle Videos gesehen habe, habe ich eine Menge Feedback zu den einzelnen Videos, die ich per E-Mail senden werde. Die Schlussfolgerung ist jedoch, dass dies so viel mehr ist als eine Einführung in Redux. Sie behandeln Code-Praktiken und Komponentenarchitektur und mehr. Es ist wirklich toll und sehr pädagogisch. Ich denke, die Videos lassen sich jedoch in drei Gruppen einteilen. Redux Basic, Redux hinter den Kulissen und Redux mit Reagieren.

Für kommende Videos möchte ich weniger auf spezifische Konzepte reagieren und mehr auf asynchrone Aktionen und Tests.

Auffallend gut gemacht, weiter so! :)

In Video 21 stellst du fest, dass die TodoApp-Komponente keine Klasse mehr sein muss, sondern eine Funktion sein kann. Es wäre toll, wenn Sie erklären könnten, wie Sie zu dieser Erkenntnis gekommen sind – warum ist dies ein geeigneter Kandidat für eine Funktionskomponente und welchen Nutzen hat dies?

Das ist so gut.

Punkt 3 in der Liste von @smashercosmo würde ich auch gerne wissen.

was @wpannell gesagt hat! Unit-Tests/TDD!

Würde auch gerne Videos zu den Themen sehen, die in den erweiterten Dokumenten behandelt werden.

Was interessiert Sie speziell in Bezug auf Unit-Tests?
Die Lektionen 5, 11, 12 geben eine Vorstellung davon, wie die Reduzierstücke getestet werden.

...Das ist eine gute Frage. Würde sich der Prozess sehr ändern, wenn es sich um Mokka-Tests handelt?

Nicht wirklich. Aber ich denke, das ist ein gutes Thema für eine Reihe von fortgeschrittenen Lektionen. Unit Testing Reducer, Action Creator, Komponenten etc.

Erstens tolle Videos. Redux bereits verstanden, aber es war erfrischend.
Wenn Sie fortgeschrittenere Videos erstellen, kann ich asynchrone Aktionen / Middleware vorschlagen.
Denken Sie nicht, dass Unit-Tests wirklich eine Abdeckung benötigen. Sie können einfach Ihre Reduzierfunktionen aufrufen und darauf aufbauen?

Ja, ich denke, es ist wirklich nicht viel anderes, als die expect s in Mokka-Tests einzuwickeln. :Daumen hoch:

Zum Glück ist alles so einfach!

Unveränderlichkeit mit Objekt-ID-Hashes (zB [post._id]: {...post} ).

Ich verlasse mich zu sehr auf eine reduce Funktion, um ein Array von API-Entitäten zu nehmen und damit einen ID-Hash zu erzeugen. Ich weiß, dass normalizr einiges davon bewältigen wird, aber ich hätte gerne Videos, die den EggheadIO-Videos ähneln, in denen Sie uns von Punkt A nach B bringen. Es ist nicht nur eine Redux-basierte Sache, sondern ist stark miteinander verflochten.

@raquelxmoss

In Video 21 stellst du fest, dass die TodoApp-Komponente keine Klasse mehr sein muss, sondern eine Funktion sein kann. Es wäre toll, wenn Sie erklären könnten, wie Sie zu dieser Erkenntnis gekommen sind – warum ist dies ein geeigneter Kandidat für eine Funktionskomponente und welchen Nutzen hat dies?

Das war eigentlich eine schlampige Unterrichtsplanung meinerseits. Ich habe erst zu spät gemerkt, dass ich es von Anfang an zu einem funktionalen Bestandteil hätte machen können. Der Vorteil der Verwendung von Funktionen gegenüber Klassen ist die Einfachheit, also tun Sie dies jederzeit. Wenn Sie keine Lifecycle-Hooks wie componentDidMount oder state benötigen, verwenden Sie grundsätzlich funktionale Komponenten.

Ich würde eine Lektion, wie wir diese Codeteile in eine tatsächliche Verzeichnisstruktur aufteilen können, als hilfreich empfinden. Ich weiß, dass es wahrscheinlich funktionieren wird, solange alles vorhanden ist, aber vielleicht empfohlene Konventionen zur Benennung von Ordnern (Komponente / Container / Speicher / Reduzierer usw.), welche Arten von Dateien in welchen Ordner gehen usw.

Ich hätte auch gerne eine erweiterte Reduzierzusammensetzung.

Wiederverwendung komplexer Komponenten (die aus einem Reduzierer oder mehreren Reduzierern, einer Reihe von Aktionen, Aktionserstellern, möglicherweise dem Zugriff auf eine serverseitige API, mehreren React-Komponenten bestehen - wie Redux-Form, aber eher real-app-spezifisch). Dazu gehört auch die Organisation einer modularen Verzeichnisstruktur.

Habe das Ganze gesehen, sehr gut! Ich schätzte die Verwendung der ES6/7-Syntax ( Object.assign -like), React 0.14-Funktionskomponenten und das Vermeiden von unveränderlichen Dingen.

Vielleicht ein Video, das die empfohlene Codearchitektur erklärt.

Und das Dokument aktualisieren, um ES6/7-Syntaxen zu verwenden? (Sind PR in dieser Richtung willkommen?)

Unit-Tests, API-Middleware erstellen, OAuth/eine Art Benutzerauthentifizierung mit Redux durchführen, Immutable mit Redux verwenden (wie man es einrichtet, Best Practices usw.)

Diese Serie dient als großartige Einführung in Redux, den Einzelatomzustand und verwandte Philosophien. Ich dachte, Sie haben gute Arbeit geleistet, die Kernprinzipien zu berücksichtigen und gleichzeitig eine kognitive Überlastung zu vermeiden. Die Umgebung, in der Sie gearbeitet haben, ist auch leicht reproduzierbar, was den praktischen Teil umso zugänglicher macht.

@gaearon Was hältst du davon, Aktionen in den Beispielvideos von Anfang an als Möchtegern-Standard { type: string, payload: Object } strukturieren? Ich spreche vom Beispiel der Zählerliste, bei dem die Nutzlast auf das Aktionsobjekt selbst gelegt wird; { type: string, index: number } . Das sieht für mich nach einem Anti-Muster aus.

Was halten Sie davon, Aktionen in den Beispielvideos von Anfang an als Möchtegern-Standard { type: string, payload: Object } zu strukturieren? Ich spreche vom Beispiel der Zählerliste, bei dem die Nutzlast auf das Aktionsobjekt selbst gelegt wird; { Typ: Zeichenfolge, Index: Zahl }. Das sieht für mich nach einem Anti-Muster aus.

Es ist in keinster Weise ein Anti-Muster. Es ist ein normales Aktionsobjekt. FSA ist in Ordnung, aber es ist eine _Konvention_. Nichts in Redux selbst hängt von dieser Konvention ab oder profitiert von dieser, daher möchten wir sie nicht erzwingen.

Früher dachten die Leute alle möglichen magischen Dinge über payload , source in der ursprünglichen Flux-Dokumentation. Sie kopierten diese Dinge blindlings, ohne zu verstehen, warum sie existieren, und prüften sorgfältig, ob sie sie überhaupt brauchen. Später beschwerten sie sich darüber, dass Flux komplex und ausführlich sei, obwohl sie in vielen Fällen die ausführlichen (aber nicht wesentlichen) Teile selbst kopierten.

In diesen Lektionen unterrichte ich nur die wesentlichen Teile von Redux. Beachten Sie, dass ich keine Konstanten einführe – weil die Leute sich zu sehr auf sie konzentrieren und übersehen, dass sie nicht wirklich wichtig sind. Sie werden die Vorteile von Konstanten eher verstehen, nachdem Sie einige Tippfehler in Strings gemacht haben, anstatt sie von Anfang an in die Tutorial-Videos aufzunehmen. Ich denke, das Gleiche gilt für andere Konventionen wie die FSA – verwenden Sie sie auf jeden Fall, wenn Sie es bequem finden, aber ich werde sie nicht predigen, wenn die Lektionen es nicht verlangen.

@gaearon OK, dann bin ich bei dir, in der Hoffnung, dass diejenigen, die sich an den einfachen unstrukturierten Ansatz

@sompylasar

Ich denke, Beispiele zeigen Konventionen besser als Video-Tutorials. Beispiele sind das rechthaberische Land von „Hier ist, wie ich einen Code um diese Prinzipien herum strukturiere“ und Videos handeln von diesen Prinzipien selbst. Aus diesem Grund werden Sie in verschiedenen Beispielen unterschiedliche Konventionen sehen, und bevor sie ein Projekt starten, sehen sich die meisten Leute verschiedene Beispiele an, um einen Eindruck von verschiedenen Möglichkeiten zu bekommen, dies zu tun.

Es ist auch absolut nichts Unstrukturiertes daran, der FSA nicht zu folgen. { type: 'STUFF', id: 1 } ist nicht von Natur aus schlechter als { type: 'STUFF', payload: { id: 1 } } . Es ist nur eine Frage des Geschmacks und (manchmal) der Werkzeugkonvention. Aktionsobjekte um payload weniger zu halten, macht die Arbeit mit ihnen nicht schwieriger.

Wir haben eine Handvoll Redux-Unit-Testing-Lektionen, die demnächst auf egghead erscheinen

Wir haben JEDE Redux-Lektion für einige Zeit verschoben, damit Dan den ersten Crack haben kann. Das Warten hat sich absolut gelohnt, und dann noch einiges mehr.

"Eine Anwendung erstellen mit Idiomatic Redux" wäre ein wunderbarer Aufbaukurs 👍

@joelhooks die klingen beide fantastisch!

Ich würde gerne sehen, dass Sie ein Projekt mit Webpack und Hot Reloading einrichten, anstatt jsbin zu verwenden. Nehmen Sie dies mit in die reale Welt. Ich weiß, es ist nicht spezifisch für Redux, aber ich denke, es würde gut passen und du bist der richtige Mann, um das zu lehren :)

@kevinrenskers es ist keine Videoserie, aber wenn du Lust hast, etwas zu sezieren, gibt es ein paar wirklich großartige Beispiel-Boilerplates, auf die du verweisen kannst!

Diejenigen, die nach einer Projektstruktur für Dans Beispiel und Webpack-Konfiguration gefragt haben.

Bitte überprüfen Sie dies https://github.com/urbanvikingr/todo.

Ich habe mich verpflichtet, Redux mit React doc zu aktualisieren, um es an Dans Code aus den Videos anzupassen. Es wird in den nächsten zwei Wochen fertig sein - mein Ferienprojekt :) - stay tuned.

Meine Wunschliste zu Egghead.io-Videos:
Aktions-/Reduzierertest mit Jasmine
Deep-Dive auf Middleware (Thunk / Versprechen)

Die Screencasts sind eine sehr nützliche Einführung in Redux. Was ich gerne hören würde, ist die Redux-Methode für Routing und serverseitiges Rendering

@grigio Vielleicht interessiert Sie diese Diskussion https://github.com/rackt/redux/issues/1145 über Routing

@urbanvikingr danke, abonniert. Die Umfrage scheint geschlossen, aber ich hätte mit #1168 gestimmt

Die Lektionen sind eigentlich ziemlich gut, aber es lenkt ab, dass wenn Sie "Laden" sagen, es wie "Hausarbeit" klingt.

Jeder hier hat es bemerkt und wurde davon abgelenkt. Sie sind einfach zu politisch korrekt, um das anzusprechen. Also ja, ich habe mich entschieden, _dieser_ Typ zu sein, für den Fall, dass es sonst niemand tun würde :)

Irgendwann werde ich besser Englisch sprechen. Das ist im Moment das Beste, was ich tun kann ;-)

@gaearon Du hast verdammt gute Arbeit geleistet, Redux zu erklären. Ein großes Lob an Sie und Ihre Open-Source-Errungenschaften.

Erstaunliche Lektionen. Besonders gut hat mir gefallen, wie Sie jede der Kernfunktionen von Redux von Grund auf neu implementiert haben, indem Sie den Quellcode lesen. Die Abordnung von jemand anderem, der beeindruckt war, wie klar die Tutorials und die gesamte Dokumentation für Redux sind. Als jemand, der zwei Jahre Frontend-Fortschritte nachgeholt hat, war es bisher schwer, die Konzepte zu verstehen, aber die Dokumente waren dabei erstaunlich hilfreich. Weiter so und danke!

(Hören Sie auch nicht

@ianstormtaylor
Es ist übrigens kein Akzent :)

Es war mir auch egal, aber ich war auf jeden Fall abgelenkt!

Auf der anderen Seite _hatte_ ich als jemand, der sechs Fremdsprachen studiert hat, immer Wert darauf, eine Sprache richtig zu sprechen, und deshalb bin ich persönlich dankbar, wenn jemand auf meine Fehler hinweist.

Hey @gaearon ,

Ich habe deinen Kurs absolut geliebt. Gute Arbeit! Es war sehr hilfreich.

Ich habe meinem letzten Egghead-Kurs drei Redux-Testvideolektionen hinzugefügt:
https://egghead.io/series/react-testing-cookbook

Ich hoffe, dass sie all die erstaunliche Arbeit, die Sie geleistet haben, loben werden!

Solider Kurs!

Verbessert nicht nur das Redux-Wissen, sondern auch das Wissen über moderne Praktiken insgesamt! Mach weiter so gute Sachen :+1: :tada:

hey, habe gerade festgestellt, dass es in den Videos keinen Link/Verweis auf den Code gibt. Vielleicht offensichtlich und vielleicht einfach genug, könnten Benutzer die Videos einfach kopieren; Aber ich denke, viele Leute könnten von einem Repos mit dem genauen Code in den Videos profitieren - warum nicht?

Für Egghead-Abonnenten stehen Code-Snippets für jede Lektion zur Verfügung. :-)
Die Videos sind kostenlos, aber die Plattform muss Geld verdienen, damit sie in mehr Kurse investieren, Ausrüstung an die Ausbilder senden, die Videos hosten, die Website verbessern und so weiter kann.

Das heißt, wir haben einen examples/todos Ordner, der ziemlich genau zum Kurs passt.

... cool, das fehlt mir dann? Link(s) gesucht...

@gaearon entschuldigt sich, habe

Übrigens haben sich einige Leute darüber beschwert, dass Transkripte ungenau sind.
Bitte senden Sie PRs, um sie zu beheben: https://github.com/eggheadio/egghead-redux-transcripts

@gaearon Ich

Mein Vorschlag für das zukünftige Redux-Videotraining wäre also eine erweiterte Komposition, ein tieferes Eintauchen in das Refactoring und definitiv die Verwendung von Reselect. Sie scheinen eine Intuition zu haben, wann Sie umgestalten müssen. Da funktionale Programmierung so eng mit Redux verbunden ist, wäre es wirklich nützlich, einige Tipps von Ihnen zu erhalten, wann eine Refaktorierung erforderlich ist und wie Sie eine Funktion identifizieren können, die eine Sache gut macht.

In der App, die ich baue, habe ich mehrere große Datensammlungen und ich muss sie in Tabellen ablegen und Dinge wie Sortieren und Paginieren der Daten tun. Ich habe Schwierigkeiten zu entscheiden, wann Selektoren und wann Aktionen zum Erstellen verwendet werden sollen. Derzeit habe ich die Aktion USERS_SORT_TABLE und SORT_TABLE, da die Benutzer einen Status aus der Tabelle "erben". Ich habe dies getan, weil ich nicht wollte, dass eine SORT_TABLE-Aktion für einen Todo-Speicher vom Benutzerspeicher sortiert wird.

Ich weiß, dass meine Lösung nicht DRY ist, aber ich bin mir nicht sicher, wie ich es richtig mache. So wie es aussieht, muss ich für jedes Geschäft, in dem ich eine Tabelle füllen möchte, eine Aktion "SOMETHING"_SORT_TABLE erstellen, von der ich weiß, dass sie falsch ist, aber ich weiß nicht, wie es richtig ist. Ein weiterer Nebeneffekt ist, dass meine Aktionsnamen riesig werden, weil ich verschiedene Geschäfte trennen muss, indem ich ihren Namen der Aktion voranstelle. Das kann nicht stimmen.

Hier ist ein Beispielcode:

/* actions.js */
// ...
export const USER_MOVE_COLUMN = 'USER_MOVE_COLUMN'

export function userMoveColumn (columnIndex, moveToIndex) {
  return {
    type: USER_MOVE_COLUMN,
    columnIndex,
    moveToIndex
  }
}

export const DATA_TABLE_MOVE_COLUMN = 'DATA_TABLE_MOVE_COLUMN'
// ...

/* reducers.js */
// ...
export default function user (state=userInitialState, action) {
  switch (action.type) {
    // ...
    case USER_MOVE_COLUMN:
      return dataTable(state, assign(
        action,
        {type: DATA_TABLE_MOVE_COLUMN}
      ))
    // ...
    default:
      return state
  }
}
// ...
export default function dataTable (
  state=dataTableInitialState,
  action,
  key='dataTable')
{
  switch (action.type) {
    // ...
    case DATA_TABLE_MOVE_COLUMN:
      return {
        ...state,
        [key]: {
          ...state[key],
          columns: move(
            state[key].columns, action.columnIndex, action.moveToIndex
          )
        }
      }
    // ...
    default:
      return state
  }
}

Sie können also sehen, dass ich eine Abhängigkeit zwischen der Tabelle und dem "Modell" -Speicher erstellt habe, die ich nicht haben sollte (der Modellspeicher muss den Sammlungsschlüssel für sein Array von Objekten verwenden). Und die dataTable manipuliert den Zustand des "übergeordneten" Reducers, was nicht der Fall sein sollte. Mir kam der Gedanke, dass ich dort einen Selektor verwenden muss, aber als ich dies schrieb, versuchte ich zu vermeiden, einen großen Shop zu duplizieren, nur um zu ändern, was in der Benutzeroberfläche sichtbar war.

Momentan kämpfe ich also damit, Reselect zu lernen, um einige dieser Probleme zu lösen, und Refactoring-Techniken, um einige der anderen zu lösen. Der erste Redux-Kurs war genug, um mich gefährlich zu machen. Jetzt möchte ich lernen, wie man es richtig macht. :)

Ich hoffe, das war hilfreich und nicht zu ausführlich. Versuchen, klares, ehrliches Feedback zu geben.

Für alle, die mir helfen könnten, ich habe bereits /examples/real-world/reducers in einem anderen Kommentar von Dan gefunden und überarbeite derzeit einige der oben beschriebenen Probleme. Ich wollte nicht, dass Sie Ihre Zeit damit verschwenden, zu helfen, wenn ich eine Lösung gefunden hätte.

Danke für die Warnung :)

Die Integration der Redux-Devtools in mein Projekt war eine große Qual für mich.. Ich hätte (und werde) eine Egghead-Serie geschätzt, die beschreibt, was es da draußen gibt und wie / wann man sie verwendet. Ich habe die PR gelesen, in der Sie beschreiben, wann was zu verwenden ist.

Für alle anderen, die mit einigen der oben beschriebenen Probleme zu kämpfen haben, habe ich ein Projekt erstellt, mit dem Sie die meisten, wenn nicht sogar alle Boilerplates in Redux sowie Namespace-Aktionen entfernen können. Siehe das hier

@granteagon Sind das nicht Reduzierer zu Action-Erstellern? Eines der zentralen Designprinzipien in Redux ist, dass _Reduzierer von Aktionen entkoppelt werden sollten_. Jeder Reduzierer kann auf jede Aktion hören. Es gibt keine 1:1-Zuordnung zwischen ihnen. Andernfalls ist es für verschiedene Teile des Zustandsbaums schwierig, ihren Zustand als Reaktion auf dieselben Aktionen unabhängig voneinander zu ändern.

Ich habe festgestellt, dass die meisten Leute, die Wrapper oder Abstraktionen zusätzlich zur Action/Reducer-Erstellung erstellen, davon ausgehen, dass sie immer direkt miteinander gekoppelt sind. Zugegeben, in meiner App haben bisher _die meisten_ meiner Aktionen genau einen entsprechenden Teil der Handhabungslogik, aber es gab definitiv mehrere, bei denen mehrere Teile des Baums aktualisiert werden mussten.

@gaearon @markerikson Es verbindet Reduzierer mit Action-Erstellern. In 90% der Fälle ist das jedoch in Ordnung oder sogar erwünscht. Die anderen 10% der Zeit können Sie immer noch einen handcodierten Ansatz verwenden. Ich werde jedoch über das, was Sie gesagt haben, nachdenken und es für die zukünftige Entwicklung berücksichtigen.

@granteagon @gaearon

Nachdem ich eine lokale Abstraktion verwendet habe, die reduxr ähnelt, würde ich argumentieren, dass es hier keine zusätzliche Kopplung gibt. Nichts erzwingt eine 1:1-Zuordnung zwischen Aktionen und Reduzierern. Sie können immer noch zwei Reduzierer in zwei verschiedenen Slices haben, die sich dieselbe Aktion anhören:

const counterReducersA = {
  // this counter increments by 1 each time
  increment: (state, action) => state + 1
}

const counterReducersB = {
  // this counter increments by 2 each time
  increment: (state, action) => state + 2
}

const counterA = reduxr(counterReducersA, 0);
const counterB = reduxr(counterReducersB, 0);

const rootReducer = combineReducers({
  counterA: counterA.reducer,
  counterB: counterB.reducer
});

store.dispatch(counterA.action.increment());  // increments both counters

Wenn Sie mehr als eine "Reduzierer" -Funktion haben, die denselben Namen hat (dh auf dieselbe Aktion reagiert), müssen beide natürlich implizit "erwarten", dass die Aktionsnutzlast eine bestimmte Form hat --- was völlig analog ist zu zwei Reduzierern in Vanilla Redux, die beide dieselbe type Konstante handhaben --- beide müssen dieselbe Aktionsform erwarten.

Vielleicht habe ich falsch verstanden, was du mit Kopplung meinst ,

Ich denke, das Anzeigen eines asynchronen Flusses ohne Middleware vor dem Anzeigen der Thunk-Implementierung könnte hilfreich sein.

Etwas verwandt, aber während die Dokumentation wahnsinnig hilfreich war, hat mich diese Aussage auf der Seite async-flows im Nachhinein wirklich aus der Bahn geworfen: "Ohne Middleware unterstützt Redux Store nur synchronen Datenfluss."

@battaile : Das liegt daran, dass es wahr ist :) Ohne Middleware muss jede Asynchronität vollständig außerhalb von Redux auftreten (also höchstwahrscheinlich in Ihrer UI-Schicht, wie z. B. React-Komponenten). Jedes Mal, wenn Sie store.dispatch aufrufen, würde die Aktion direkt zur Reducer-Funktion übergehen, Go nicht übergeben, keine $200 einsammeln, unterwegs keine Stopps für AJAX-Aufrufe machen.

Store Enhancer ermöglichen es Ihnen, Funktionen wie dispatch mit Ihrer eigenen Version zusammenzufassen, und so bietet applyMiddleware die Abstraktion einer "Middleware-Pipeline", bevor etwas die dispatch Funktion des echten Geschäfts erreicht . Das bietet im Grunde eine Lücke, aus der Sie herausspringen und alle asynchronen Dinge tun können, die Sie möchten, _innerhalb_ des Standard-Redux-Flows.

Ohne Middleware könnten Sie also immer noch völlig asynchrone Dinge tun ... es müsste nur alles völlig getrennt von allem passieren, was tatsächlich mit Redux zu tun hat.

das liegt daran, dass es wahr ist :)

Ich habe nicht gesagt, dass es falsch ist, ich sagte, es hat mich aus der Bahn geworfen :)

Ich wollte nur so etwas wie Folgendes tun, was zu implizieren schien, dass ich es nicht konnte:

const mapDispatchToProps = (dispatch) => ({
  onclick(searchTerm) {
    dispatch(actions.requestOrders(searchTerm));

    return fetch('http://localhost:49984/Order/Search?search=' + searchTerm)
      .then(response => response.json()).then(response => {
        dispatch(actions.receiveOrders(searchTerm, response));
      })
      .catch((err) => {
        dispatch(actions.receiveOrdersError('An error occurred during search: ' + err.message));
      });
  },
});

Mir ist klar, dass dies leicht hässlich werden könnte, aber konzeptionell denke ich, dass es nützlich ist, es zu sehen. Oder zumindest war es in meinem Fall.

Ich stimme zu, dass "Redux Store ohne Middleware nur synchronen Datenfluss unterstützt." ist irreführend.

Technisch gesehen, wenn Sie zwischen "innen" und "außen" unterscheiden möchten, könnte die Aussage stimmen, aber wenn sie glauben lässt, dass die einzige Möglichkeit zur Asynchronisierung darin besteht, Middleware hinzuzufügen, können wir sie vielleicht umformulieren oder näher erläutern es.

Ja, der Unterschied besteht darin, dass das asynchrone Verhalten technisch gesehen eher auf Komponentenebene stattfindet als "innerhalb" von dispatch . Ein kleiner Unterschied, aber ein gültiger.

Ich glaube nicht, dass irgendjemand argumentiert, dass die Aussage technisch nicht korrekt ist.

@markerikson Nur neugierig, ob Sie konkrete Beispiele haben, bei denen die Unterscheidung zwischen Innen und Außen wichtig ist?

Ein Beispiel könnte sein, wenn Sie möchten, dass Middleware in der Kette _bevor_ Ihre asynchrone Middleware Ihren gesendeten Thunk (oder Versprechen usw.) sehen kann. Ich bin mir nicht sicher, _was_ diese Middleware _tun würde_, aber ich denke, es ist machbar, so etwas zu wollen.

Mmm ... ich bin mir bei "konkreten" Beispielen nicht sicher. Insgesamt ist die Unterscheidung zwischen "draußen" und "insie" eine Frage, ob es passiert, _bevor_ Sie dispatch das erste Mal aufrufen, oder _nach_. Wenn es sich um "außen" und "vorher" handelt, ist Ihre gesamte Asynchronität und Logik mehr an die Ansichtsebene gebunden, sei es React, Angular oder etwas anderes. Wenn es sich um "innerhalb" und "nachher" handelt, befinden sich Ihre Asynchronität und Logik auf der Speicherebene und sind _nicht_ an die Ansichtsebene gebunden.

Dies ist eigentlich ein Großteil des Punktes, den ich heute in einer Reddit-Diskussion zu betonen versucht habe: https://www.reddit.com/r/reactjs/comments/4spbip/has_anyone_inserted_a_controllerpresenter_layer/ .

Die Frage "Welche Aktionen sende ich und wann sende ich sie?" ist ein Kernelement Ihrer Geschäftslogik, wobei die andere Hälfte lautet: "Wie aktualisiere ich meinen Status als Reaktion auf diese Aktionen?". Wenn sich die Aktionsverwaltung in Thunks und Sagas und dergleichen befindet, spielt es keine Rolle, ob dieser Code von einer React-Komponente, einem Angular-Controller, einem jQuery-Klickhandler, einer Vue-Komponenteninstanz oder etwas anderem gestartet wurde. Ihre Kernlogik befindet sich außerhalb der UI-Schicht, und die UI-Schicht ist eigentlich nur dafür verantwortlich, die benötigten Daten aus dem Store zu ziehen, anzuzeigen und Benutzereingaben in einen App-Logik-Funktionsaufruf umzuwandeln.

In diesem Sinne würde ich sagen, dass die Frage "innen" vs "außen" von Bedeutung ist, da es eine konzeptionelle Unterscheidung ist, ob Ihre Logik auf App-Ebene oder auf UI-Ebene lebt.

@markerikson danke, dass du mich bei dieser Fragestellung unterstützt hast. Auch auf die Gefahr hin, als argumentativ zu wirken, möchte ich die Vorstellung, dass dies "App-Ebene" vs. "UI-Ebene" ist, ein wenig zurückdrängen.

Hinweis: Der Einfachheit halber verwende ich thunk , um einen abriträren Middleware-Ansatz für die Asynchronisierung darzustellen, egal ob es sich tatsächlich um Redux-Thunk oder Redux-Promise oder was auch immer handelt.

Ihre UI-Schicht verbindet nur Benutzerinteraktionen mit Handlern. Wenn jemand auf eine Schaltfläche klickt, ist Ihre Benutzeroberfläche so manipuliert, dass _some_ Handler aufgerufen wird. Oft erhält die Komponente diese Handler als Requisiten --- vielleicht zum Beispiel ein gebundener Aktionsersteller. Die Benutzeroberfläche ist sich nicht bewusst, was passiert, wenn sie einen Handler aufruft – sie ruft sie einfach auf.

Für die UI-Schicht macht es keinen Unterschied, ob der "Handler" eine Funktion absetzt (die von der Middleware verarbeitet wird) oder ob er einen asynchronen Aufruf ausführt und _dann_ eine einfache Aktion absetzt --- die UI ist völlig agnostisch (oder zumindest _kann_ agnostisch sein)

Ein großer Teil Ihrer "App" befindet sich in diesen "Handlern", unabhängig davon, ob Sie Thunks verwenden oder nicht. In einer typischen React-/Redux-App sind diese "Handler" oft eine Art Aktionsersteller. Sie könnten all Ihre asynchronen Sachen als Thunks schreiben und sie versenden. Oder Sie könnten all Ihre asynchronen Sachen als Funktionen schreiben, die dispatch als Argument akzeptieren. Aus der Sicht der Komponente ist es entweder someHandler(dispatch) ODER dispatch(someHandler()) , oder im Fall von Erstellern gebundener Aktionen, die von einer höheren Stelle weitergegeben wurden, sind es in beiden Fällen nur someHandler() . Sie könnten eine Version von bindActionCreators erstellen, die diesen Unterschied zur UI-Ebene vollständig maskieren würde.

Wenn Sie mir eine Reaction/Redux-Anwendung geben, die mit Action-Erstellern unter Verwendung von Redux-Thunk geschrieben wurde, könnte ich Redux-Thunk vollständig austauschen und einen Nicht-Middleware-Ansatz verwenden, ohne _grundsätzlich_ die UI-Schicht zu ändern. (Anmerkung: Ich beschönige, wo/wie Sie getState injizieren, aber ich _glaube_, dass das hier ein kleines Detail ist).

Daher kann ich nur schwer akzeptieren, dass die Unterscheidung zwischen "innen" und "außen" "App-Ebene" oder "UI-Ebene" ist.

Ich freue mich über die Diskussion und hoffe, dass ich nicht negativ rüberkomme.

Dieser Kurs ist großartig. Schließen Sie dies, damit die Leute ihre Kommentare an das Community-Notizen-Repository für den Kurs richten können: https://github.com/tayiorbeii/egghead.io_redux_course_notes

Schaut euch auch unbedingt die nächste Serie an, die Dan zusammengestellt hat! https://egghead.io/courses/building-react-applications-with-idiomatic-redux

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen