React: ¿El estado de configuración dentro de eventos discretos debe hacer que se ejecute la limpieza?

Creado en 5 mar. 2019  ·  3Comentarios  ·  Fuente: facebook/react

Este error es bastante confuso:

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

Creo que sucede porque fn programado por setInterval(fn, 0) salta frente a la limpieza del efecto [running] causada por setRunning(false) . Entonces, el intervalo aún se dispara, sobrescribiendo setLapse(0) que sucedió durante el evento con su setLapse(someValue) .

Esto me recuerda el problema descrito en https://github.com/facebook/react/issues/14750#issuecomment -460409609, o al menos una parte de él:

De hecho, este problema existe incluso para las pulsaciones de teclas de React regulares (y otros eventos "discretos"). La solución a eso sería eliminar los efectos pasivos antes de que obtengamos un evento discreto.

Pero aquí, parece que esto no sería suficiente porque el efecto cambia como resultado del clic, no antes. Entonces, ¿ setState dentro de un evento discreto también debería eliminar el efecto pasivo? Parece que no. (Eso frustraría el propósito de retrasarlos).

¿Así que esto funciona según lo diseñado, y la solución es solo useLayoutEffect cuando el tiempo importa? ¿O la solución rAF?

Hooks Question

Comentario más útil

Un enfoque es enviar el reinicio solo una vez que el temporizador se detenga realmente, es decir, en el efecto. Si desea que siempre muestre cero en el mismo marco, siempre puede mostrar cero cuando la ejecución sea falsa.

Sin embargo, como casi siempre, esto se modela mejor como reductor. El reductor puede rechazar fácilmente que las actualizaciones caduquen cuando cree que está en un estado detenido y también puede realizar la lógica para restablecerlo.

Todos 3 comentarios

El problema es que el temporizador en sí no es un evento discreto. Los eventos discretos solo se garantizan en relación con otros eventos discretos. No creo que eso sea lo que quieres aquí.

Detener el temporizador es una operación asincrónica ya que todos los estados establecidos son asincrónicos. Entonces, algo más puede entrar antes de que se lave.

Este es un caso en el que useLayoutEffect no soluciona completamente el problema. Ciertamente no en modo concurrente, pero esto también es incompleto en modo de sincronización. Si no fuera un temporizador, pero digamos un evento de enfoque, entonces puede dispararse dentro de un lote antes de que se vacíe, lo que tendría el mismo problema.

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

Se trata de en qué orden se agregan las cosas a la cola.

Un enfoque es enviar el reinicio solo una vez que el temporizador se detenga realmente, es decir, en el efecto. Si desea que siempre muestre cero en el mismo marco, siempre puede mostrar cero cuando la ejecución sea falsa.

Sin embargo, como casi siempre, esto se modela mejor como reductor. El reductor puede rechazar fácilmente que las actualizaciones caduquen cuando cree que está en un estado detenido y también puede realizar la lógica para restablecerlo.

¿Fue útil esta página
0 / 5 - 0 calificaciones