React: Sollte das Setzen des Status in diskreten Ereignissen dazu fĂŒhren, dass die Bereinigung ausgefĂŒhrt wird?

Erstellt am 5. MĂ€rz 2019  Â·  3Kommentare  Â·  Quelle: facebook/react

Dieser Fehler ist ziemlich verwirrend:

https://twitter.com/kentcdodds/status/1102659818660102145

Ich denke, es passiert, weil fn das von setInterval(fn, 0) wurde, vor der von setRunning(false) verursachten [running] Effektbereinigung springt. Das Intervall wird also immer noch ausgelöst und ĂŒberschreibt setLapse(0) , das wĂ€hrend des Ereignisses passiert ist, mit seinen setLapse(someValue) .

Das erinnert mich an das in https://github.com/facebook/react/issues/14750#issuecomment -460409609 beschriebene Problem oder zumindest an einen Teil davon:

TatsĂ€chlich besteht dieses Problem sogar bei normalen React-TastenanschlĂ€gen (und anderen „diskreten“ Ereignissen). Die Lösung dafĂŒr wĂ€re, passive Effekte zu spĂŒlen, bevor wir ein diskretes Ereignis erhalten.

Aber hier scheint dies nicht ausreichend zu sein, da der Effekt durch den Klick kippt, nicht vorher. Sollte also setState innerhalb eines diskreten Events auch den passiven Effekt spĂŒlen? Scheint nicht. (Das wĂŒrde den Zweck, sie zu verzögern, zunichte machen.)

Dies funktioniert also wie geplant, und die Lösung ist nur useLayoutEffect wenn das Timing wichtig ist? Oder die rAF-Lösung?

Hooks Question

Hilfreichster Kommentar

Ein Ansatz besteht darin, den Reset erst dann auszulösen, wenn der Timer tatsĂ€chlich stoppt, dh im Effekt. Wenn Sie möchten, dass immer Null im selben Frame angezeigt wird, können Sie immer Null anzeigen, wenn die AusfĂŒhrung falsch ist.

Dieser ist jedoch wie fast immer besser als Reduzierer modelliert. Der Reduzierer kann das Verfallen von Aktualisierungen leicht ablehnen, wenn er denkt, dass er sich in einem gestoppten Zustand befindet, und auch die Logik ausfĂŒhren, um ihn tatsĂ€chlich zurĂŒckzusetzen.

Alle 3 Kommentare

Das Problem ist, dass der Timer selbst kein diskretes Ereignis ist. Diskrete Ereignisse werden nur in Bezug auf andere diskrete Ereignisse garantiert. Ich glaube nicht, dass du das hier willst.

Das Stoppen des Timers ist ein asynchroner Vorgang, da alle gesetzten ZustĂ€nde asynchron sind. Es kann also noch etwas anderes reinkommen, bevor es gespĂŒlt wird.

Dies ist ein Fall, in dem useLayoutEffect das Problem nicht vollstĂ€ndig behebt. Im Concurrent-Modus sicher nicht, aber auch im Sync-Modus ist das lĂŒckenhaft. Wenn es sich nicht um einen Timer, sondern beispielsweise um ein Fokusereignis handelt, kann das innerhalb eines Stapels ausgelöst werden, bevor dieser geleert wird, was das gleiche Problem hĂ€tte.

setRunning(false); // I would like to add a stop of this timer to the queue to be performed later
setLapse(0); // I would like to add an operation to set lapse to zero later
// lots of random stuff that can happen before the batch flushes
// This might also queue an operation to set lapse to something else
// actual rendering
// If concurrent mode, lots of other random stuff that can happen while rendering
// This might also queue an operation to set lapse to something else
// Actually do all that work in order

Es geht darum, in welcher Reihenfolge Dinge in die Warteschlange aufgenommen werden.

Ein Ansatz besteht darin, den Reset erst dann auszulösen, wenn der Timer tatsĂ€chlich stoppt, dh im Effekt. Wenn Sie möchten, dass immer Null im selben Frame angezeigt wird, können Sie immer Null anzeigen, wenn die AusfĂŒhrung falsch ist.

Dieser ist jedoch wie fast immer besser als Reduzierer modelliert. Der Reduzierer kann das Verfallen von Aktualisierungen leicht ablehnen, wenn er denkt, dass er sich in einem gestoppten Zustand befindet, und auch die Logik ausfĂŒhren, um ihn tatsĂ€chlich zurĂŒckzusetzen.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen