Reaktionskomponente, die bei Zustandsänderung nicht erneut gerendert wird
Lesezeit: 7 Minuten
Ich habe eine Reaktionsklasse, die an eine API geht, um Inhalte abzurufen. Ich habe bestätigt, dass die Daten zurückkommen, aber es wird nicht erneut gerendert:
Dazu möchte ich noch den enorm simplen, aber ach so leicht gemachten Schreibfehler hinzufügen:
this.state.something = 'changed';
… und dann nicht verstehen, warum es nicht rendert und googelt und auf diese Seite kommt, nur um zu erkennen, dass Sie hätten schreiben sollen:
this.setState({something: 'changed'});
React löst nur dann ein erneutes Rendern aus, wenn Sie es verwenden setState um den Zustand zu aktualisieren.
Das ist genau das Problem, das ich hatte. Es ist seltsam, dass sie keine Warnung ausgeben, da sie eine ausgeben, wenn sie versuchen, Requisiten zu aktualisieren.
– AndrewJM
13. Dezember 2015 um 22:38 Uhr
@AndrewJM Sie können keine Warnung ausgeben. Sie könnten, wenn Sie schreiben würden this.state = 'something' weil Sie den Setter für schlagen würden stateaber im obigen Beispiel trifft der Code auf den Getter, der ein Objekt zurückgibt und dann ein Feld für ein Objekt festlegt, das nur eine Kopie des Zustands ist.
– Stijn de Witt
23. Juni 2017 um 21:37 Uhr
@TheBigCheese Schreiben Sie besser eine (gute) Frage dazu. Es gibt Leute, die helfen können, aber nicht hier in den Kommentaren einer anderen Frage.
– Stijn de Witt
13. November 2019 um 19:17 Uhr
@StijndeWitt Ich habe mich bei Stackoverflow angemeldet, um Ihre Antwort zu verbessern. Danke Bruder ;D
– Esterlinkof
20. Mai 2020 um 22:10 Uhr
Sehr wichtiges Konzept für Anfänger, um es zu verstehen und sich zu merken.
– Unbesiegbarer Muffi
29. Juli 2021 um 10:34 Uhr
Mein Szenario war etwas anders. Und ich denke, dass viele Neulinge wie ich ratlos wären – also hier teilen.
Meine Zustandsvariable ist ein Array von JSON-Objekten, die wie folgt mit useState verwaltet werden:
const [toCompare, setToCompare] = useState([]);
Wenn Sie jedoch toCompare mit setToCompare wie in der folgenden Funktion aktualisieren, wird das erneute Rendern nicht ausgelöst. Und das Verschieben auf eine andere Komponente hat auch nicht funktioniert. Nur wenn ein anderes Ereignis ein erneutes Rendern auslösen würde, wurde die aktualisierte Liste angezeigt.
Dies war die Lösung für mich. Grundsätzlich – das Zuweisen des Arrays war das Kopieren der Referenz – und React würde das nicht als Änderung sehen – da die Referenz auf das Array nicht geändert wird – nur Inhalt darin. Also im folgenden Code – einfach das Array mit Slice kopiert – ohne Änderung – und es nach Mods wieder zugewiesen. Funktioniert einwandfrei.
Hoffe es hilft jemandem wie mir. Bitte lassen Sie es mich wissen, wenn Sie der Meinung sind, dass ich falsch liege – oder es einen anderen Ansatz gibt.
Danke im Voraus.
Wow, mein Problem war fast eine Kopie. Vielen Dank!
– stevejboyer
13. Mai 2021 um 7:23 Uhr
Ja ich auch. In ES6 können wir den Spread-Operator verwenden, um den Zustand zu klonen, um React aufzufordern, die Zustandsänderung zu bestätigen: let newItems = [...items];
– S Meaden
25. Mai 2021 um 20:20 Uhr
Ja Meaden, das ist richtig. Ich stimme zu. Halten Sie es für sinnvoll, meinen Lösungsbeitrag zu aktualisieren, um diesen Punkt als besseren Weg einzufügen, damit die Leute das als allgemeinere Methode zur Umgehung dieses Problems verwenden? Gerne behilflich sein.
– KManisch
1. Juni 2021 um 6:51 Uhr
haha, auch hier ein Durchschlagsproblem. KOMISCH!
– Crashtor
10. August 2021 um 17:28 Uhr
Auch hier eine Durchschlagskopie!… halt, am Ende kopieren wir immer den Code von jemand anderem, inklusive deren Probleme 😉
– Nelson García
17. Februar um 16:56 Uhr
Michelle Tilley
Das liegt daran, dass die Antwort von chrome.runtime.sendMessage ist asynchron; Hier ist die Reihenfolge der Operationen:
var newDeals = [];
// (1) first chrome.runtime.sendMessage is called, and *registers a callback*
// so that when the data comes back *in the future*
// the function will be called
chrome.runtime.sendMessage({...}, function(deals) {
// (3) sometime in the future, this function runs,
// but it's too late
newDeals = deals;
});
// (2) this is called immediately, `newDeals` is an empty array
this.setState({ deals: newDeals });
Wenn Sie das Skript mit dem Debugger anhalten, geben Sie der Erweiterung Zeit, den Rückruf aufzurufen. Bis Sie fortfahren, sind die Daten angekommen und es scheint zu funktionieren.
Um das zu beheben, möchten Sie das tun setState Aufruf, nachdem die Daten von der Chrome-Erweiterung zurückkommen:
var newDeals = [];
// (1) first chrome.runtime.sendMessage is called, and *registers a callback*
// so that when the data comes back *in the future*
// the function will be called
chrome.runtime.sendMessage({...}, function(deals) {
// (2) sometime in the future, this function runs
newDeals = deals;
// (3) now you can call `setState` with the data
this.setState({ deals: newDeals });
}.bind(this)); // Don't forget to bind(this) (or use an arrow function)
[Edit]
Wenn dies bei Ihnen nicht funktioniert, sehen Sie sich die anderen Antworten auf diese Frage an, die andere Gründe erläutern, warum Ihre Komponente möglicherweise nicht aktualisiert wird.
Duh! Ich hätte wissen müssen, dass dies der Fall war, als die Debugger-Zeile es behoben hat. Die Bindung (dies) war das, was ich vermisst habe, als ich das zum ersten Mal versuchte. Danke, toller ausführlicher Kommentar!
– brandonhilkert
19. September 2014 um 15:54 Uhr
Ein weiterer ach so einfacher Fehler, der für mich die Ursache des Problems war: Ich hatte meinen eigenen geschrieben shouldComponentUpdate -Methode, die die neue Statusänderung, die ich hinzugefügt hatte, nicht überprüfte.
In meinem Fall habe ich angerufen this.setState({}) korrekt, aber meine Funktion war nicht daran gebunden, also funktionierte es nicht. Hinzufügen .bind(this) zum Funktionsaufruf oder Tun this.foo = this.foo.bind(this) im Konstruktor behoben.
Ich habe dieses Problem. Alle Funktionen sind ordnungsgemäß im Konstruktor gebunden.
– Der große Käse
12. November 2019 um 15:49 Uhr
Gus T Hintern
Mein Problem war, dass ich „React.PureComponent“ verwendet habe, wenn ich „React.Component“ hätte verwenden sollen.
Ich habe dieses Problem. Alle Funktionen sind ordnungsgemäß im Konstruktor gebunden.
– Der große Käse
12. November 2019 um 15:49 Uhr
Um den Status ordnungsgemäß zu aktualisieren, sollten Sie das Array nicht mutieren. Sie müssen eine Kopie des Arrays erstellen und dann den Zustand mit dem kopierten Array festlegen.
const [deals, setDeals] = useState([]);
function updateDeals(deal) {
const newDeals = [...deals]; // spreading operator which doesn't mutate the array and returns new array
newDeals.push(deal);
// const newDeals = deals.concat(deal); // concat merges the passed value to the array and return a new array
// const newDeals = [...deals, deal] // directly passing the new value and we don't need to use push
setDeals(newDeals);
}
Warum wird die Komponente durch direkte Mutation nicht erneut gerendert?
– Thamaraiselvam
16. April um 16:16 Uhr
@Thamaraiselvam Höchstwahrscheinlich liegt es daran, dass die Reaktion das Objekt nur als Zeiger sieht. React kann also nicht erkennen, dass sich das Objekt geändert hat, bevor sich der Zeiger ändert.
– Sören Jensen
5. Juni um 12:25 Uhr
10862000cookie-checkReaktionskomponente, die bei Zustandsänderung nicht erneut gerendert wirdyes