Arrays im State aktualisieren
Arrays sind in JavaScript veränderlich (mutable), aber Sie sollten sie als unveränderlich (immutable) behandeln, wenn Sie sie im State speichern. Genau wie bei Objekten müssen Sie, wenn Sie ein im State gespeichertes Array aktualisieren möchten, ein neues erstellen (oder eine Kopie eines bestehenden anfertigen) und dann den State so setzen, dass er das neue Array verwendet.
Sie werden lernen
- Wie Sie Elemente in einem Array im React-State hinzufügen, entfernen oder ändern
- Wie Sie ein Objekt innerhalb eines Arrays aktualisieren
- Wie Sie das Kopieren von Arrays mit Immer weniger repetitiv gestalten
Arrays ohne Mutation aktualisieren
In JavaScript sind Arrays einfach eine andere Art von Objekt.Wie bei Objekten,sollten Sie Arrays im React-State als schreibgeschützt behandeln.Das bedeutet, dass Sie Elemente innerhalb eines Arrays nicht neu zuweisen sollten, wie z.B.arr[0] = 'bird', und Sie sollten auch keine Methoden verwenden, die das Array mutieren, wiepush()undpop().
Stattdessen sollten Sie jedes Mal, wenn Sie ein Array aktualisieren möchten, einneuesArray an Ihre State-Setter-Funktion übergeben. Dazu können Sie ein neues Array aus dem ursprünglichen Array in Ihrem State erstellen, indem Sie dessen nicht-mutierende Methoden wiefilter()undmap()aufrufen. Dann können Sie Ihren State auf das resultierende neue Array setzen.
Hier ist eine Referenztabelle für gängige Array-Operationen. Wenn Sie mit Arrays innerhalb des React-States arbeiten, müssen Sie die Methoden in der linken Spalte vermeiden und stattdessen die Methoden in der rechten Spalte bevorzugen:
Alternativ können SieImmer verwenden, wodurch Sie Methoden aus beiden Spalten nutzen können.
Fallstrick
Leider sindsliceundspliceähnlich benannt, aber sehr unterschiedlich:
sliceermöglicht es, ein Array oder einen Teil davon zu kopieren.splicemutiertdas Array (um Elemente einzufügen oder zu löschen).
In React werden Sieslice(ohnep!) viel häufiger verwenden, weil Sie Objekte oder Arrays im State nicht mutieren möchten.Objekte aktualisierenerklärt, was Mutation ist und warum sie für den State nicht empfohlen wird.
Zu einem Array hinzufügen
push()mutiert ein Array, was Sie nicht wollen:
Erstelle stattdessen einneuesArray, das die bestehenden Elementeundein neues Element am Ende enthält. Es gibt mehrere Möglichkeiten, dies zu tun, aber die einfachste ist die Verwendung der...Spread-Syntax für Arrays:
Jetzt funktioniert es korrekt:
Die Array-Spread-Syntax ermöglicht es dir auch, ein Element voranzustellen, indem du esvordas ursprüngliche...artistssetzt:
Auf diese Weise kann Spread die Aufgabe vonpush()(Hinzufügen am Ende eines Arrays) undunshift()(Hinzufügen am Anfang eines Arrays) übernehmen. Probiere es in der Sandbox oben aus!
Aus einem Array entfernen
Der einfachste Weg, ein Element aus einem Array zu entfernen, ist, esherauszufiltern. Mit anderen Worten, du erzeugst ein neues Array, das dieses Element nicht enthält. Verwende dazu diefilter-Methode, zum Beispiel:
Klicke ein paar Mal auf die Schaltfläche „Delete“ und sieh dir ihren Klick-Handler an.
Hier bedeutetartists.filter(a => a.id !== artist.id)„Erstelle ein Array, das aus denjenigenartistsbesteht, deren IDs sich vonartist.idunterscheiden“. Mit anderen Worten, die „Delete“-Schaltfläche jedes Künstlers filtertdiesenKünstler aus dem Array heraus und fordert dann ein erneutes Rendern mit dem resultierenden Array an. Beachte, dassfilterdas ursprüngliche Array nicht verändert.
Ein Array transformieren
Wenn du einige oder alle Elemente des Arrays ändern möchtest, kannst dumap()verwenden, um einneuesArray zu erstellen. Die Funktion, die du anmapübergibst, kann anhand der Daten oder des Index (oder beidem) jedes Elements entscheiden, was damit geschehen soll.
In diesem Beispiel enthält ein Array die Koordinaten von zwei Kreisen und einem Quadrat. Wenn du die Schaltfläche drückst, werden nur die Kreise um 50 Pixel nach unten verschoben. Dies geschieht durch die Erzeugung eines neuen Datenarrays mitmap():
Elemente in einem Array ersetzen
Es ist besonders häufig der Fall, dass man ein oder mehrere Elemente in einem Array ersetzen möchte. Zuweisungen wiearr[0] = 'bird'mutieren das ursprüngliche Array, daher solltest du stattdessen auch hiermapverwenden.
Um ein Element zu ersetzen, erstelle mitmapein neues Array. Innerhalb deinesmap-Aufrufs erhältst du den Elementindex als zweites Argument. Verwende ihn, um zu entscheiden, ob du das ursprüngliche Element (das erste Argument) oder etwas anderes zurückgeben möchtest:
Einfügen in ein Array
Manchmal möchten Sie ein Element an einer bestimmten Position einfügen, die weder am Anfang noch am Ende liegt. Dazu können Sie die...Array-Spread-Syntax zusammen mit derslice()-Methode verwenden. Dieslice()-Methode ermöglicht es Ihnen, einen "Slice" (Ausschnitt) des Arrays zu schneiden. Um ein Element einzufügen, erstellen Sie ein Array, das den Slicevordem Einfügepunkt, dann das neue Element und dann den Rest des ursprünglichen Arrays enthält.
In diesem Beispiel fügt die Einfügen-Schaltfläche immer am Index1ein:
Andere Änderungen an einem Array vornehmen
Es gibt einige Dinge, die Sie mit der Spread-Syntax und nicht-mutierenden Methoden wiemap()undfilter()allein nicht tun können. Zum Beispiel möchten Sie möglicherweise ein Array umkehren oder sortieren. Die JavaScript-Methodenreverse()undsort()mutieren das ursprüngliche Array, daher können Sie sie nicht direkt verwenden.
Sie können jedoch zuerst das Array kopieren und dann Änderungen daran vornehmen.
Zum Beispiel:
Hier verwenden Sie die[...list]Spread-Syntax, um zuerst eine Kopie des ursprünglichen Arrays zu erstellen. Da Sie nun eine Kopie haben, können Sie mutierende Methoden wienextList.reverse()odernextList.sort()verwenden oder sogar einzelne Elemente mitnextList[0] = "something"zuweisen.
Allerdingskönnen Sie, selbst wenn Sie ein Array kopieren, vorhandene Elementeinnerhalbdavon nicht direkt mutieren.Dies liegt daran, dass das Kopieren flach ist – das neue Array enthält dieselben Elemente wie das ursprüngliche. Wenn Sie also ein Objekt innerhalb des kopierten Arrays ändern, mutieren Sie den vorhandenen Zustand. Zum Beispiel ist Code wie dieser problematisch.
ObwohlnextListundlistzwei verschiedene Arrays sind, zeigennextList[0]undlist[0]auf dasselbe Objekt.Durch die Änderung vonnextList[0].seenändern Sie also auchlist[0].seen. Dies ist eine Zustandsmutation, die Sie vermeiden sollten! Sie können dieses Problem auf ähnliche Weise lösen wie bei derAktualisierung verschachtelter JavaScript-Objekte– indem Sie die einzelnen Elemente, die Sie ändern möchten, kopieren, anstatt sie zu mutieren. So geht's.
Objekte innerhalb von Arrays aktualisieren
Objekte befinden sich nichtwirklich"innerhalb" von Arrays. Sie mögen im Code "innerhalb" erscheinen, aber jedes Objekt in einem Array ist ein separater Wert, auf den das Array "zeigt". Deshalb müssen Sie vorsichtig sein, wenn Sie verschachtelte Felder wielist[0]ändern. Die Kunstwerkliste einer anderen Person könnte auf dasselbe Element des Arrays zeigen!
Wenn Sie verschachtelten Zustand aktualisieren, müssen Sie Kopien von dem Punkt aus erstellen, an dem Sie aktualisieren möchten, und zwar bis zur obersten Ebene.Sehen wir uns an, wie das funktioniert.
In diesem Beispiel haben zwei separate Kunstwerklisten denselben Anfangszustand. Sie sollen isoliert sein, aber aufgrund einer Mutation wird ihr Zustand versehentlich geteilt, und das Ankreuzen eines Kästchens in einer Liste beeinflusst die andere Liste:
Das Problem liegt in Code wie diesem:
Obwohl das ArraymyNextListselbst neu ist, sind dieElemente selbstdieselben wie im ursprünglichen ArraymyList. Das Ändern vonartwork.seenändert also dasursprünglicheKunstwerk-Element. Dieses Kunstwerk-Element befindet sich auch inyourList, was den Fehler verursacht. Solche Fehler können schwer nachzuvollziehen sein, aber zum Glück verschwinden sie, wenn man Mutationen des States vermeidet.
Sie könnenmapverwenden, um ein altes Element durch seine aktualisierte Version zu ersetzen, ohne es zu mutieren.
Hier ist...die Objekt-Spread-Syntax, die verwendet wird, umeine Kopie eines Objekts zu erstellen.
Mit diesem Ansatz wird keines der vorhandenen State-Elemente mutiert, und der Fehler ist behoben:
Im Allgemeinensollten Sie nur Objekte mutieren, die Sie gerade erstellt haben.Wenn Sie einneuesKunstwerk einfügen würden, könnten Sie es mutieren, aber wenn Sie mit etwas arbeiten, das bereits im State ist, müssen Sie eine Kopie erstellen.
Kompakte Update-Logik mit Immer schreiben
Das Aktualisieren verschachtelter Arrays ohne Mutation kann etwas repetitiv werden.Genau wie bei Objekten:
- Im Allgemeinen sollten Sie den State nicht mehr als ein paar Ebenen tief aktualisieren müssen. Wenn Ihre State-Objekte sehr tief verschachtelt sind, sollten Sie sie vielleichtanders strukturieren, sodass sie flach sind.
- Wenn Sie Ihre State-Struktur nicht ändern möchten, ziehen Sie vielleicht die Verwendung vonImmervor, das es Ihnen ermöglicht, mit der bequemen, aber mutierenden Syntax zu schreiben und sich um die Erstellung der Kopien für Sie kümmert.
Hier ist das Art Bucket List-Beispiel mit Immer neu geschrieben:
Beachten Sie, wie mit ImmerMutationen wieartwork.seen = nextSeenjetzt in Ordnung sind:
Das liegt daran, dass Sie nicht denursprünglichenZustand mutieren, sondern ein speziellesdraft-Objekt, das von Immer bereitgestellt wird. Ebenso können Sie mutierende Methoden wiepush()undpop()auf den Inhalt desdraftanwenden.
Im Hintergrund konstruiert Immer den nächsten Zustand immer von Grund auf neu, entsprechend den Änderungen, die Sie amdraftvorgenommen haben. Dadurch bleiben Ihre Event-Handler sehr prägnant, ohne jemals den Zustand zu mutieren.
Zusammenfassung
- Sie können Arrays in den State setzen, aber Sie können sie nicht verändern.
- Erstellen Sie anstatt ein Array zu mutieren eineneueVersion davon und aktualisieren Sie den State darauf.
- Sie können die Array-Spread-Syntax
[...arr, newItem]verwenden, um Arrays mit neuen Elementen zu erstellen. - Sie können
filter()undmap()verwenden, um neue Arrays mit gefilterten oder transformierten Elementen zu erstellen. - Sie können Immer verwenden, um Ihren Code prägnant zu halten.
Try out some challenges
Challenge 1 of 4:Update an item in the shopping cart #
Fill in the handleIncreaseClick logic so that pressing ”+” increases the corresponding number:
