Closed fernandomk6 closed 1 year ago
Só para complementar professor. Na documentação do react é possivel encontrar algo como
Isso significa que, dependendo da implementação, pode ser possível que as duas chamadas a this.setState sejam agrupadas em uma única atualização de estado, em vez de serem aplicadas individualmente.
Isso confunde bastante... de forma "grosseira"... é assíncrono ou não; Ou depende; E se depende depende exatamente de que? Como eu conseguiria "prever" o comportamento, se será assíncrono ou não. Pois isso faz total diferença na hora de implementar uma funcionalidade.
A interface reage instantaneamente apos uma chamada de setState
? Como se a função atual fosse pausada.
E continuasse apos a renderização...
Ou a renderização proveniente do setState ocorre apenas depois de toda a função ser lida?
Como você pode perceber estou bastante confuso com relação a essas questões e um pouco preocupado por que é um conceito muito importante.
Oi @fernandomk6! Excelente questão, vou detalhar aqui os pontos de dúvida =)
Antes de tudo, sobre essa frase aqui:
Usei async/await e fetch, ao invés de thens/catch e jax. Acredito que isso não venha a causar grandes diferenças.
Não tem problema. Se você sabe como usar o fetch
, o resultado final será o mesmo =)
setState
por baixo dos panosSobre o setState
: sim, ele é sempre assíncrono! Mas o que isso significa, de forma prática?
O setState
ser assíncrono não significa que a execução dele acontece "depois" de tudo. Na verdade, toda função que é assíncrona é executada sempre no momento em que ela é chamada. O que normalmente nós fazemos é passar para essa função uma outra função via argumento que, essa sim, será executada somente quando a ação assíncrona esperada finalizar.
Então, ao executar o this.setState()
, você está dizendo para o React que, naquele momento, você quer que o componente seja atualizado, mas com os novos dados, com os valores que você passou via argumento para o setState
.
O que é assíncrono nesse caso é, de fato, a atualização do estado: quando o setState
é executado, o React vai "re-renderizar" o componente. Se você estiver usando uma classe, a re-renderização é basicamente a chamada sequencial dos métodos render
(com o this.state
já atualizado) e então é chamado o lifecicle componentDidUpdate
.
Mas a sua função anterior, que chamou o setState
continua rodando, ela ainda não terminou de executar tudo o que tinha para executar, por isso que, ao chamar o setState
, você consegue ver o resultado "na hora".
Como a sua função continua executando, ela ainda não consegue acessar os dados novos do estado via this.state
, apesar do componente já ter sido re-renderizado, pois para isso acontecer, a função teria que ser executada de novo.
É aí que está a parte "assíncrona" do setState
: se o this.state.isFetching
era false
quando você executou a função, e dentro da função você executa um this.setState({ isFetching: true })
, logo após esse setState
, na mesma função, você não vai ver o this.state.isFetching
como true
. Ele vai continuar como false
, exatamente porque essa atualização do estado acontece de forma assíncrona.
Então o fluxo de execução da sua função vai continuar normalmente: desde que você não tente acessar o this.state
dentro dessa função, achando que o estado vai estar atualizado nesse objeto, tudo vai acontecer como deveria.
Em resumo: a interface responde o mais rápido possível à chamada do setState
(de forma assíncrona, ou seja: o seu código não para de ser executado quando você chama o setState
), mas dentro da função que você chamou o setState
, você nunca vai ter acesso ao estado atualizado via this.state
.
Deu pra entender a ideia?
setState
Esse comportamento que a documentação está ser referindo, é quando você chama o setState
mais de uma vez, de forma seguida. Exemplo:
this.setState({ isFetching: true })
this.setState({ isFetching: false })
this.setState({ isFetching: true })
this.setState({ isFetching: false })
this.setState({ isFetching: true })
Se você fizer algo nesse sentido, o React vai fazer o componente re-renderizar uma única vez, já que a chamada do setState
é assíncrona, então é possível saber que uma função foi executada mais de uma vez em período curto de tempo.
Se for esse o caso, o React não vai executar 5 re-renders, mas somente 1, com o valor mais recente para o isFetching
.
Não é o caso do que estamos fazendo: nós chamamos o setState
, e logo após fazemos um request que vai demorar um pouco para ser executado. O próximo setState
só vai acontecer quando o request terminar, então a re-renderização vai acontecer como esperado =)
Ficou tudo claro? Se ainda restou qualquer dúvida, fique muito à vontade para perguntar, porque essa parte é muito importante sim :D
Ficou uma dúvida sim professor.
Eu já entendi que, o objeto this.state
é "imutável" durante a mesma execução da função. Ou seja, ele só vai conter os
novos valores passados na próxima execução da função. Ou seja, não adianta fazer chamadas "acumuladas" pois o state ainda não foi atualizado.
Eu também compreendi que, a parte assíncrona no setState é a mudança do objeto state. Ela so vai acontecer, após a função ser executada (método render ser executado).
Eu também entendi que o react, quando necessário, vai "unir" as chamadas de setStates e executar apenas um render, a fim de otimizar a performance.
A dúvida que ainda me resta é a seguinte: O this.setState
chama, de forma síncrona o método render?
Em que momento o método render encadeado pelo this.setState
será de fato executado, durante a função?
depois dela... ou em paralelo?
handleClick (e) {
this.setState({ aState: e.target.value })
// this.render() é invocado pelo setState de forma síncrona agora
// ...O que está aqui a baixo será executado após o render ser executado?
}
De forma mais resumida, o render que é encadeado pelo setState, pode ser, executado, durante a
execução da função atual? Como o exemplo acima, setState(); this.render() ...resto do código
Eu entendo bem o conceito de callbacks e funções sendo executadas de forma assíncrona, mas nesse exemplo em especifico, parece que tanto o render como a função atual, são executadas em paralelo, o que não é possível pois o JS executa uma coisa de cada vez.
Ou seja, não adianta fazer chamadas "acumuladas" pois o state ainda não foi atualizado.
Na verdade dá pra fazer, eu mostro isso com mais detalhes no módulo 2, e depois no módulo 4 também, com hooks =)
Mas em resumo, é só passar uma função para o setState
, ao invés do objeto que você vai atualizar. A função vai conter o estado atualizado, ainda que o componente não tenha re-renderizado =)
A dúvida que ainda me resta é a seguinte: O this.setState chama, de forma síncrona o método render?
Sim!
Em que momento o método render encadeado pelo this.setState será de fato executado, durante a função? depois dela... ou em paralelo?
Isso não vai fazer diferença para o seu código, pois você só vai usar o this.setState
quando quiser que haja alguma mudança na sua view (que é renderizada pelo retorno do método render
.
Se você quiser ter uma ideia melhor de como isso funciona por baixo dos panos, eu fiz um vídeo mostrando como funciona o hook useState
. A ideia é basicamente a mesma com classe: a diferença é que, ao invés de re-executar a função, o React vai re-executar só o método render
da classe. Dá uma olhada no vídeo e me diga se essa parte fica mais clara:
https://www.youtube.com/watch?v=yb-fBApqWSw
Eu entendo bem o conceito de callbacks e funções sendo executadas de forma assíncrona, mas nesse exemplo em especifico, parece que tanto o render como a função atual, são executadas em paralelo, o que não é possível pois o JS executa uma coisa de cada vez.
Sim, o JS vai executar uma instrução por vez. E com o this.setState
não é diferente: quando você executa essa função, o que for síncrono dentro dessa função vai ser executado "na mesma hora". Depois, o que é assíncrono (atualização do estado e chamada do render
) vai ser "agendado" para executar no futuro (event loop), e o próximo código continua rodando.
No caso do seu exemplo, o próximo código é um request, que é assíncrono. Como o request é assíncrono, a execução dele também vai para o event loop e o restante do código continua rodando (aqui já abre um espaço para executar a atualização do estado e a execução do render
, chamados pelo setState
anteriormente).
Mas assim: isso não deveria ser uma preocupação, pois isso acontece por baixo dos panos, e você não tem controle sobre essa execução (e nem deveria).
O que você precisa saber mesmo é como todo o processo ocorre. Por outro lado, eu entendo que a dúvida de como isso funciona por baixo dos panos pode trazer um pouco de ansiedade, por isso eu gravei o vídeo que eu passei ali em cima.
Assista e me diga se ainda ficou alguma dúvida, ok? :D
O que você precisa saber mesmo é como todo o processo ocorre.
É exatamente isso professor, eu só quero pode entender claramente a ordem das execuções pois acredito que isso seja muito importante ao estar desenvolvendo aplicações.
Eu estou fazendo em paralelo algumas aplicações simples e lendo a doc do react, e estou vendo que é comum um componente manipular vários estados e muitas vezes esses estados são atualizados juntos. E a parte assíncrona ainda não estava muito clara para mim.
Mas você conseguiu tirar a minha dúvida completamente com essa última explicação.
Era como eu imaginava, porém, eu não estava me atentando ao fato do request que eu fiz, também ser assíncrono, e ele ficou entre os 2 setState. Dessa forma, foi feito duas renderização ao invés de uma.
Caso ficassem juntos, o react faria apenas um render para otimizar.
Irei sim ver seu vídeo professor, mas já me ajudou muito com essas informações. Acredito que o vídeo irá esclarecer mais.
Obrigado.
Massa @fernandomk6! Que bom que ficou claro :D Qualquer dúvida, fique muito à vontade para mandar aqui =)
Duvida
Fala Professor, tudo bem?
Estou com dúvidas no fluxo de execução de 2 ou mais
setState
que estão sendo executados um após o outro.Descrição
Na aplicação github app, mostrada no modulo 1 part 2, na aula 46, o senhor mostra como exibir uma mensagem de loading, enquanto, o request do search, não é concluído.
Porém, nesse método
handleSearch
são executados mais de umsetState
, e como eu sei que, osetState
é assíncrono, eu gostaria que se possível, o senhor me esclarecesse o fluxo de execução, dossetState
que ocorrem nesse método.Usei async/await e fetch, ao invés de thens/catch e jax. Acredito que isso não venha a causar grandes diferenças.
Código
O que acontece
Esse código ocorre conforme esperado.
Ao pressionar enter, a mensagem de loading acontece (o state foi "passado para frente" alterando a renderização dos filhos). Após alguns segundos, o loading some, e é renderizado os dados do usuário.
Ou seja, existe um "tempo", entre as chamadas dos setState e consequentemente de seus renders.
Esse "tempo" é de fato o que me causa dúvida com relação a natureza assíncrono do
setState
Como eu vejo
Eu sei que
setState
é assíncrono, então eu imagino que, todas as chamadas desetState
serão executadas, após toda a leitura da funçãohandleSearch
. Imagino a call assim:handleSearch
handleSearch
setState 1
: inicio loadingsetState 2
: fetch concluidosetState 3
: loading concluídoPorém, se fosse assim, não haveria um "tempo perceptível" entre as chamadas
setState
. Tempo entre exibição do loading e exibição dos resultados.Em resumo
O
setState
parece ter um comportamento síncrono poís, imediatamente ao setar o stateisFetching
, a interface responde, e imediatamente ao setar o stateuserInfo
a interface responde.Como eu até então venho vendo-os como assíncronos eu imaginava que essas execuções ocorrecem imadiatamente uma apos a outra... como se fossem acumulados para serem executados depois numa especie de macro ou micro task...
Desculpa a mensagem longa professor. Apesar do codigo está funcionando, eu preciso ter isso bem claro, pois, é praticamente a base do react o setState e seus efetios.
Desde já agradeço professor.
@fdaciuk