In dem Kapitel zum Entwerfen der Statusform wird in den Dokumenten vorgeschlagen, Ihren Status in einem Objekt mit ID zu speichern:
Behalten Sie jede Entität in einem Objekt bei, das mit einer ID als Schlüssel gespeichert ist, und verwenden Sie IDs, um auf sie von anderen Entitäten oder Listen zu verweisen.
Sie sagen weiter
Stellen Sie sich den Status der App als Datenbank vor.
Ich arbeite an der Statusform für eine Liste von Filtern, von denen einige geöffnet sind (sie werden in einem Popup angezeigt) oder ausgewählte Optionen haben. Als ich "Stellen Sie sich den Status der App als Datenbank vor" las, dachte ich darüber nach, sie als JSON-Antwort zu betrachten, da sie von einer API zurückgegeben wird (die selbst von einer Datenbank unterstützt wird).
Also dachte ich daran
[{
id: '1',
name: 'View',
open: false,
options: ['10', '11', '12', '13'],
selectedOption: ['10'],
parent: null,
},
{
id: '10',
name: 'Time & Fees',
open: false,
options: ['20', '21', '22', '23', '24'],
selectedOption: null,
parent: '1',
}]
In den Dokumenten wird jedoch ein ähnliches Format vorgeschlagen
{
1: {
name: 'View',
open: false,
options: ['10', '11', '12', '13'],
selectedOption: ['10'],
parent: null,
},
10: {
name: 'Time & Fees',
open: false,
options: ['20', '21', '22', '23', '24'],
selectedOption: null,
parent: '1',
}
}
Theoretisch sollte es keine Rolle spielen, solange die Daten serialisierbar sind (unter der Überschrift "State") .
Also ging ich glücklich mit dem Ansatz der Anordnung von Objekten vor, bis ich meinen Reduzierer schrieb.
Mit dem objektschlüsselgesteuerten ID-Ansatz (und der liberalen Verwendung der Spread-Syntax) wird der OPEN_FILTER
Teil des Reduzierers
switch (action.type) {
case OPEN_FILTER: {
return { ...state, { ...state[action.id], open: true } }
}
Während der Array-of-Objects-Ansatz ausführlicher ist (und von der Hilfsfunktion abhängt)
switch (action.type) {
case OPEN_FILTER: {
// relies on getFilterById helper function
const filter = getFilterById(state, action.id);
const index = state.indexOf(filter);
return state
.slice(0, index)
.concat([{ ...filter, open: true }])
.concat(state.slice(index + 1));
}
...
Meine Fragen sind also dreifach:
1) Ist die Einfachheit des Reduzierers die Motivation für den objektschlüsselgesteuerten Ansatz? Gibt es andere Vorteile für diese Zustandsform?
und
2) Es scheint, dass der objektschlüsselgesteuerte Ansatz es schwieriger macht, mit Standard-JSON-Ein- / Ausgängen für eine API umzugehen. (Deshalb habe ich mich in erster Linie für das Array von Objekten entschieden.) Wenn Sie sich also für diesen Ansatz entscheiden, verwenden Sie einfach eine Funktion, um sie zwischen dem JSON-Format und dem Statusformformat hin und her zu transformieren? Das scheint klobig. (Wenn Sie diesen Ansatz befürworten, ist dies Teil Ihrer Argumentation, dass dies weniger klobig ist als der oben beschriebene Reduzierer für Objektarrays?)
und
3) Ich weiß, dass Dan Abramov Redux so entworfen hat, dass es theoretisch unabhängig von Zustandsdatenstrukturen ist (wie in "Konventionell ist der Zustand der obersten Ebene ein Objekt oder eine andere Schlüsselwertsammlung wie eine Karte, aber technisch kann es jede sein." Typ , " Betonung meiner). Aber angesichts der obigen Ausführungen ist es nur "empfohlen", ein Objekt mit ID zu versehen, oder gibt es andere unvorhergesehene Schwachstellen, auf die ich stoßen werde, wenn ich eine Reihe von Objekten verwende, die es so machen, dass ich das einfach abbrechen sollte planen und versuchen, bei einem Objekt zu bleiben, das mit einem ID versehen ist?
quelle
sort_by
?const sorted = _.sortBy(collection, 'attribute');
Antworten:
Q1: Die Einfachheit des Reduzierers resultiert daraus, dass das Array nicht durchsucht werden muss, um den richtigen Eintrag zu finden. Das Array nicht durchsuchen zu müssen, ist der Vorteil. Selektoren und andere Datenzugriffsberechtigte können und werden häufig über diese Elemente zugreifen
id
. Das Durchsuchen des Arrays nach jedem Zugriff wird zu einem Leistungsproblem. Wenn Ihre Arrays größer werden, verschlechtert sich das Leistungsproblem erheblich. Je komplexer Ihre App wird und Daten an mehreren Stellen angezeigt und gefiltert werden, desto schlimmer wird das Problem. Die Kombination kann schädlich sein. Durch den Zugriff auf die Elemente überid
ändert sich die Zugriffszeit vonO(n)
aufO(1)
, was für großen
(hier Array-Elemente) einen großen Unterschied macht.F2: Sie können verwenden
normalizr
, um bei der Konvertierung von der API zum Speicher zu helfen. Ab normalizr V3.1.0 können Sie denormalize verwenden, um in die andere Richtung zu gehen. Allerdings sind Apps häufig mehr Verbraucher als Hersteller von Daten, weshalb die Konvertierung in ein Geschäft in der Regel häufiger erfolgt.F3: Die Probleme, auf die Sie bei der Verwendung eines Arrays stoßen, sind weniger Probleme mit der Speicherkonvention und / oder Inkompatibilitäten als vielmehr Leistungsprobleme.
quelle
Das ist die Schlüsselidee.
1) Wenn Sie Objekte mit eindeutigen IDs haben, können Sie diese ID immer verwenden, wenn Sie auf das Objekt verweisen. Daher müssen Sie die Mindestdatenmenge zwischen Aktionen und Reduzierungen übergeben. Es ist effizienter als die Verwendung von array.find (...). Wenn Sie den Array-Ansatz verwenden, müssen Sie das gesamte Objekt übergeben, und das kann sehr bald chaotisch werden. Möglicherweise erstellen Sie das Objekt auf verschiedenen Reduzierungen, Aktionen oder sogar im Container neu (das möchten Sie nicht). Ansichten können immer das vollständige Objekt abrufen, auch wenn der zugehörige Reduzierer nur die ID enthält, da beim Zuordnen des Status die Sammlung irgendwo abgerufen wird (die Ansicht erhält den gesamten Status, um sie den Eigenschaften zuzuordnen). Aufgrund all dessen, was ich gesagt habe, haben Aktionen am Ende die minimale Menge an Parametern und reduzieren die minimale Menge an Informationen. Probieren Sie es aus.
2) Die Verbindung zur API sollte sich nicht auf die Architektur Ihres Speichers und Ihrer Reduzierungen auswirken. Aus diesem Grund haben Sie Maßnahmen, um die Trennung von Bedenken aufrechtzuerhalten. Fügen Sie einfach Ihre Konvertierungslogik in ein wiederverwendbares Modul ein und aus der API heraus, importieren Sie dieses Modul in die Aktionen, die die API verwenden, und das sollte es sein.
3) Ich habe Arrays für Strukturen mit IDs verwendet, und dies sind die unvorhergesehenen Konsequenzen, die ich erlitten habe:
Am Ende habe ich meine Datenstruktur geändert und viel Code neu geschrieben. Sie wurden gewarnt, bitte bringen Sie sich nicht in Schwierigkeiten.
Ebenfalls:
4) Die meisten Sammlungen mit IDs sollen die ID als Referenz für das gesamte Objekt verwenden. Dies sollten Sie nutzen. Die API-Aufrufe erhalten die ID und dann den Rest der Parameter, ebenso wie Ihre Aktionen und Reduzierungen.
quelle
Der Hauptgrund, warum Sie Entitäten in Objekten behalten möchten, die mit IDs als Schlüssel gespeichert sind (auch als normalisiert bezeichnet ), ist, dass die Arbeit mit tief verschachtelten Objekten (was Sie normalerweise von REST-APIs in einer komplexeren App erhalten) sehr umständlich ist. sowohl für Ihre Komponenten als auch für Ihre Reduzierstücke.
Es ist etwas schwierig, die Vorteile eines normalisierten Zustands anhand Ihres aktuellen Beispiels zu veranschaulichen (da Sie keine tief verschachtelte Struktur haben ). Angenommen, die Optionen (in Ihrem Beispiel) hatten ebenfalls einen Titel und wurden von Benutzern in Ihrem System erstellt. Das würde die Antwort stattdessen ungefähr so aussehen lassen:
Angenommen, Sie möchten eine Komponente erstellen, die eine Liste aller Benutzer anzeigt, die Optionen erstellt haben. Dazu müssten Sie zuerst alle Elemente anfordern, dann alle Optionen durchlaufen und zuletzt den erstellten_Benutzernamen abrufen.
Eine bessere Lösung wäre, die Reaktion zu normalisieren in:
Mit dieser Struktur ist es viel einfacher und effizienter, alle Benutzer aufzulisten, die Optionen erstellt haben (wir haben sie in entity.optionCreators isoliert, sodass wir nur diese Liste durchlaufen müssen).
Es ist auch ganz einfach, z. B. die Benutzernamen derjenigen anzuzeigen, die Optionen für das Filterelement mit der ID 1 erstellt haben:
Eine JSON-Antwort kann mit zB normalizr normalisiert werden .
Dies ist wahrscheinlich eine Empfehlung für komplexere Apps mit vielen tief verschachtelten API-Antworten. In Ihrem speziellen Beispiel spielt es jedoch keine Rolle.
quelle
map
Gibt wie hier undefiniert zurück , wenn Ressourcen separat abgerufen werden, wasfilter
s viel zu kompliziert macht. Gibt es eine Lösung?