Staat als array von Objekten vs Objekt-sortiert nach id
In dem Kapitel über Die Gestaltung der Staatlichen Form, die docs vorschlagen, um zu halten Ihren Zustand in ein Objekt sortiert nach ID:
Halten jede Person, die in einem Objekt gespeichert mit einer ID als Schlüssel, und verwenden Sie IDs, um diese zu referenzieren von anderen Personen oder Listen.
Sie gehen zu Zustand
Denken, die app ist-Zustand als eine Datenbank.
Arbeite ich an der staatlichen Form für eine Liste von filtern, von denen einige offen sein (Sie sind angezeigt in einem popup-Fenster), oder haben Sie die gewählten Optionen. Wenn ich lese "Denke an die app' s Zustand als eine Datenbank," ich dachte darüber nach, denken Sie als eine JSON-Antwort, wie es wäre, zurück von einem API (selbst-unterstützt durch eine Datenbank).
Also dachte ich mir, es als
[{
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',
}]
Aber die docs vorschlagen, ein format mehr, wie
{
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',
}
}
In der Theorie, es sollte keine Rolle spielen, solange die Daten, die serialisierbar ist (unter der überschrift "Status").
Also ging ich mit der array-of-objects Ansatz glücklich, bis ich Schreibe meine reducer.
Mit der Objekt-keyed-by-id-Ansatz (und liberale Verwendung von spread-syntax), die OPEN_FILTER
Teil der reducer wird
switch (action.type) {
case OPEN_FILTER: {
return { ...state, { ...state[action.id], open: true } }
}
In der Erwägung, dass mit der array-of-objects Ansatz, es ist die ausführlichere (und Helfer-Funktion angewiesen)
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));
}
...
Also meine Fragen sind dreifach:
1) Ist die Einfachheit der reducer die motivation für den Gang mit dem Objekt-keyed-by-id-Ansatz? Gibt es andere Vorteile, die state-Form?
und
2) Es scheint, wie das Objekt-keyed-by-id-Ansatz macht es schwieriger, befassen sich mit standard-JSON-in/out für eine API. (Das ist, warum ich ging mit dem array von Objekten in den ersten Platz.) Also, wenn Sie gehen mit diesem Konzept, haben Sie nur eine Funktion verwenden, um es zu transformieren, hin und her zwischen JSON-format und Zustand-shape-format? Das scheint umständlich. (Obwohl, wenn Sie sich dafür einsetzen, dass ein Ansatz, der Teil Ihrer Argumentation, dass das weniger klobig als die array-of-objects reducer oben?)
und
3) ich weiß, Dan Abramov entwickelt redux zu theoretisch werden Staatliche Daten-Struktur Agnostiker (wie vorgeschlagen von "Durch die Konvention, die top-level-Zustand ist ein Objekt oder eine andere Schlüssel-Wert-collection wie eine Karte, aber technisch kann jede Art," Hervorhebung von mir). Aber angesichts der oben genannten, ist es nur "empfohlen" zu halten, ein Objekt sortiert nach ID, oder gibt es andere unvorhergesehene Schmerzen Punkte, die ich dabei bin zu laufen, mit einem array von Objekten, machen Sie es so, dass ich sollte nur Abbrechen, dass plan und versuchen, den Stab mit einem Objekt sortiert nach ID?
- Dies ist eine interessante Frage, und eine, die ich hatte, nur einen Einblick zu gewähren, obwohl ich eher zu normalisieren, in der redux anstelle von arrays (rein, weil nachschlagen ist einfacher), ich finde, dass wenn man die normalisierten Ansatz Sortierung zu einem Problem, da Sie nicht die gleiche Struktur wie das array gibt Sie, so dass Sie gezwungen sind, Sortieren sich selbst.
- Ich sehe ein problem in 'Objekt-keyed-by-id" - Ansatz, allerdings ist dies nicht häufigen, aber wir haben, diesen Fall zu prüfen, während das schreiben von UI-Anwendung. So was, wenn ich die Reihenfolge ändern möchten der Entität mittels einer drag & drop-element aufgelistet, die als geordnete Liste? In der Regel "Objekt-keyed-by-id' Ansatz versagt hier, und ich würde sicher gehen mit array von Objekt-Ansatz zu vermeiden, solche großzügigen Probleme. Es könnte noch mehr sein aber dachte, dass der Austausch dieses hier
- Wie kann man Sortieren, ein Objekt aus Objekte? Dies scheint unmöglich.
- Du meinst, neben der Verwendung von so etwas wie lodash ist
sort_by
?const sorted = _.sortBy(collection, 'attribute');
- Ja. Derzeit wandeln wir die Objekte in arrays innerhalb einer vue berechnete Eigenschaft
Du musst angemeldet sein, um einen Kommentar abzugeben.
Q1: Die Einfachheit der reducer ist ein Ergebnis der nicht mit der Suche durch das array zu finden, den richtigen Eintrag. Keine lästige Suche durch das array ist im Vorteil. Selektoren und andere Daten, die Zugriffsmethoden können und oft tun, Zugriff auf diese Elemente durch
id
. Suchen müssen durch das array für jeden Zugriff wird ein performance-Problem. Wenn Ihr arrays größer werden, das performance-Problem verschlechtert steil. Auch, wie Ihre app wird immer komplexer, anzeigen und filtern von Daten in mehr Orten, das Problem verschlimmert als gut. Die Kombination kann schädlich sein. Mit dem Zugriff auf die Elemente vonid
, die Zugriffszeit ändert sich vonO(n)
zuO(1)
, die für großen
(hier array-Elemente) macht einen riesigen Unterschied.Q2: Sie können
normalizr
helfen Ihnen bei der Konvertierung von API zu speichern. Als der normalizr V3.1.0 Sie können denormalize in die andere Richtung gehen. Das heißt, die Apps sind oft mehr Verbraucher als Produzenten von Daten und als solche der Konvertierung zu speichern, erfolgt in der Regel häufiger.Q3: Die Fragen führen Sie in mit einem array nicht so viel Probleme mit dem Speicher-übereinkommen und/oder Inkompatibilitäten, aber mehr performance-Probleme.
Das ist die zentrale Idee.
1) Objekte mit eindeutigen IDs können Sie immer verwenden Sie diese id beim Verweis auf das Objekt, so dass Sie zu Durchlaufen haben, die minimale Menge von Daten zwischen Aktionen und Reduzierungen. Es ist effizienter als die Verwendung von Arrays.finden(...). Wenn Sie mithilfe der array-Ansatz, den Sie zu Durchlaufen haben, das gesamte Objekt und das kann chaotisch, sehr bald, könnten Sie am Ende die Wiederherstellung des Objekts auf verschiedene Reduzierungen, Aktionen, oder auch im container (die Sie nicht wollen, dass). Views werden immer in der Lage sein, um die vollständige Objekt, auch wenn Ihre zugehörigen reducer enthält nur die ID, da bei der Zuordnung der Staat Sie bekommen die Sammlung irgendwo (die Ansicht wird den gesamten Staat, um eine Karte zu, um die Eigenschaften). Weil alles, was ich gesagt habe, Taten am Ende mit der minimalen Anzahl von Parametern, und Reduzierstücke der minimalen Menge von Informationen, probieren Sie es aus, versuchen Sie beide Methoden und sehen Sie die Architektur endet skalierbarer und sauber mit IDs, wenn Sammlungen haben ID.
2) Die Verbindung zu der API sollte sich nicht auf die Architektur, Ihre Speicher-und Reduzierstücke, das ist, warum Sie müssen Maßnahmen, um die Trennung von Bedenken. Legen Sie einfach Ihre Konvertierung der Logik in die und aus der API in eine wiederverwendbare module, importieren Sie das Modul in den Aktionen, die die API verwenden, und dass sollte es sein.
3) ich benutzt arrays für die Strukturen mit den IDs, und das sind die unvorhersehbaren Folgen habe ich gelitten:
Landete ich die änderung meiner Daten-Struktur von und schreiben auf eine Menge von code. Sie wurden gewarnt, bitte nicht sich selbst in Schwierigkeiten.
Auch:
4) die Meisten Sammlungen mit den IDs gemeint sind, die Verwendung der ID als Referenz auf das gesamte Objekt, die Sie nutzen sollten, die. Die API-Aufrufe, wird die ID - und dann der rest der Parameter, so wird Ihre Aktionen und Reduzierungen.
Der Hauptgrund, warum Sie wollen zu halten, halten Entitäten in Objekte gespeichert und mit den IDs als Schlüssel (auch als normalisiert), ist, dass es sehr umständlich, mit zu arbeiten tief verschachtelte Objekte (das ist, was Sie erhalten in der Regel von REST-APIs in einer komplexeren app) — beide für Ihre Komponenten und Ihre Reduktionen.
Es ist ein bisschen schwer zu veranschaulichen die Vorteile einer normalisierten Zustand mit Ihrer aktuellen Beispiel (Sie nicht über eine verschachtelte Struktur). Aber lassen Sie s sagen, dass die Optionen (in deinem Beispiel) hatte auch einen Titel, und wurden von Benutzern in Ihrem system. Das würde die Antwort etwa so Aussehen statt:
Nun lassen Sie uns sagen, Sie wollten, um eine Komponente zu erstellen, die zeigt eine Liste aller Benutzer, die haben Möglichkeiten geschaffen. Das zu tun, solltest du zunächst nachfragen müssen, um alle Elemente, iteriere über jede Ihrer Möglichkeiten, und schließlich bekommen die created_by.Benutzername.
Eine bessere Lösung wäre eine Normalisierung der Reaktion, in:
Mit dieser Struktur, ist es viel einfacher, und effizienter, um eine Liste aller Benutzer, die haben Möglichkeiten geschaffen (wir haben Sie isoliert in Einrichtungen.optionCreators, so müssen wir nur noch eine Schleife über diese Liste).
Es ist auch ganz einfach zu zeigen, z.B. den Benutzernamen von denen, die haben Möglichkeiten geschaffen, die für das filter-Element mit ID 1:
Einer JSON-Antwort kann normalisiert werden, beispielsweise mit normalizr.
Ist es wahrscheinlich eine Empfehlung für die komplexeren apps mit vielen tief verschachtelten API-Antworten. In Ihrem speziellen Beispiel, obwohl es nicht wirklich wichtig, dass viel.
map
den Wert undefiniert zurückgibt, als in hier, wenn die Ressourcen separat geholt, so dassfilter
s viel zu kompliziert. Gibt es eine Lösung?