React: A configuração do estado em eventos discretos deve fazer com que a limpeza seja executada?

Criado em 5 mar. 2019  ·  3Comentários  ·  Fonte: facebook/react

Este bug é muito confuso:

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

Eu acho que isso acontece porque fn programado por setInterval(fn, 0) pula na frente da limpeza de efeito [running] causada por setRunning(false) . Portanto, o intervalo ainda dispara, sobrescrevendo setLapse(0) que aconteceu durante o evento com seus setLapse(someValue) .

Isso me lembra do problema descrito em https://github.com/facebook/react/issues/14750#issuecomment -460409609, ou pelo menos parte dele:

Na verdade, esse problema existe mesmo para pressionamentos de tecla React regulares (e outros eventos “discretos”). A solução para isso seria eliminar os efeitos passivos antes de obter um evento discreto.

Mas aqui, parece que isso não seria suficiente porque o efeito vira como resultado do clique, não antes dele. Portanto, setState dentro de um evento discreto também deve liberar o efeito passivo? Parece que não. (Isso anularia o propósito de atrasá-los.)

Então, isso está funcionando conforme planejado, e a correção é apenas useLayoutEffect quando o tempo é importante? Ou a solução rAF?

Hooks Question

Comentários muito úteis

Uma abordagem é despachar o reset apenas quando o cronômetro realmente parar, ou seja, no efeito. Se você quiser que ele sempre exiba zero no mesmo quadro, poderá sempre exibir zero quando a execução for falsa.

No entanto, como quase sempre, é melhor modelado como um redutor. O redutor pode facilmente recusar as atualizações quando ele pensa que está em um estado parado e também executar a lógica para realmente redefini-lo.

Todos 3 comentários

O problema é que o próprio cronômetro não é um evento discreto. Eventos discretos são garantidos apenas em relação a outros eventos discretos. Não acho que é isso que você quer aqui.

Parar o cronômetro é uma operação assíncrona, pois todos os estados definidos são assíncronos. Portanto, algo mais pode entrar antes de ser liberado.

Este é um caso em que useLayoutEffect não corrige totalmente o problema. Certamente não no modo simultâneo, mas também é incompleto no modo de sincronização. Se não fosse um cronômetro, mas digamos um evento de foco, ele pode disparar em um lote antes de ser liberado, o que teria o mesmo 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

É tudo sobre a ordem em que as coisas são adicionadas à fila.

Uma abordagem é despachar o reset apenas quando o cronômetro realmente parar, ou seja, no efeito. Se você quiser que ele sempre exiba zero no mesmo quadro, poderá sempre exibir zero quando a execução for falsa.

No entanto, como quase sempre, é melhor modelado como um redutor. O redutor pode facilmente recusar as atualizações quando ele pensa que está em um estado parado e também executar a lógica para realmente redefini-lo.

Esta página foi útil?
0 / 5 - 0 avaliações