O uso componentDidMount()
como uma função assíncrona é uma boa prática no React Native ou devo evitá-lo?
Preciso obter algumas informações de AsyncStorage
quando o componente é montado, mas a única maneira que sei tornar isso possível é tornar a componentDidMount()
função assíncrona.
async componentDidMount() {
let auth = await this.getAuth();
if (auth)
this.checkAuth(auth);
}
Existe algum problema com isso e outras soluções para esse problema?
reactjs
asynchronous
react-native
Mirakurun
fonte
fonte
Respostas:
Vamos começar apontando as diferenças e determinando como isso pode causar problemas.
Aqui está o código do
componentDidMount()
método de ciclo de vida assíncrono e "sincronizado" :Observando o código, posso apontar as seguintes diferenças:
async
palavras-chave: No texto datilografado, isso é apenas um marcador de código. Faz 2 coisas:Promise<void>
vez devoid
. Se você especificar explicitamente o tipo de retorno como não prometido (ex: void), o texto datilografado emitirá um erro em você.await
palavras-chave dentro do método.void
paraPromise<void>
async someMethod(): Promise<void> { await componentDidMount(); }
Agora você pode usar a
await
palavra-chave dentro do método e pausar temporariamente sua execução. Como isso:Agora, como eles poderiam causar problemas?
async
palavra-chave é absolutamente inofensiva.Não consigo imaginar nenhuma situação em que você precise fazer uma chamada para o
componentDidMount()
método, para que o tipo de retornoPromise<void>
também seja inofensivo.Chamar um método com o tipo de retorno
Promise<void>
semawait
palavra-chave não fará diferença em chamar um com o tipo de retornovoid
.Como não há métodos de ciclo de vida após
componentDidMount()
atrasar sua execução, parece bastante seguro. Mas há uma pegadinha.Digamos que o acima
this.setState({users, questions});
será executado após 10 segundos. No meio do tempo de atraso, outro ...this.setState({users: newerUsers, questions: newerQuestions});
... foram executados com sucesso e o DOM foi atualizado. O resultado foi visível para os usuários. O relógio continuou correndo e 10 segundos se passaram. O atraso
this.setState(...)
seria executado e o DOM seria atualizado novamente, dessa vez com usuários antigos e perguntas antigas. O resultado também seria visível para os usuários.=> É bastante seguro (não tenho certeza de 100%) usar
async
com ocomponentDidMount()
método Sou um grande fã e até agora não encontrei nenhum problema que me desse muita dor de cabeça.fonte
setState()
sempre possui um pequeno risco. Devemos proceder com cuidado.isFetching: true
dentro do estado de um componente. Eu só usei isso com redux, mas suponho que seja completamente válido com o gerenciamento de estado somente de reação. Embora não resolve realmente o problema do mesmo estado que está sendo atualizado em outro lugar no código ...isFetching
solução flag é bastante comum, especialmente quando queremos reproduzir algumas animações no front-end enquanto aguardamos pela resposta do back-end (isFetching: true
).Atualização em abril de 2020: o problema parece ter sido corrigido no React 16.13.1 mais recente; veja este exemplo de sandbox . Obrigado a @abernier por apontar isso.
Fiz algumas pesquisas e descobri uma diferença importante: o React não processa erros dos métodos de ciclo de vida assíncronos.
Então, se você escrever algo como isto:
seu erro será detectado pelo limite do erro e você poderá processá-lo e exibir uma mensagem normal .
Se mudarmos o código assim:
que é equivalente a isso:
então o seu erro será silenciosamente engolido . Que vergonha, reagir ...
Então, como processamos erros? A única maneira parece ser uma captura explícita como esta:
ou assim:
Se ainda queremos que nosso erro atinja o limite de erro, posso pensar no seguinte truque:
render
métodoExemplo:
fonte
Seu código é bom e muito legível para mim. Veja este artigo de Dale Jefferson, onde ele mostra um
componentDidMount
exemplo assíncrono e parece muito bom também.Mas algumas pessoas diriam que uma pessoa que lê o código pode assumir que o React faz algo com a promessa retornada.
Portanto, a interpretação deste código e se é uma boa prática ou não é muito pessoal.
Se você quiser outra solução, poderá usar promessas . Por exemplo:
fonte
async
função embutida comawait
s dentro ...?(async () => { const data = await fetch('foo'); const result = await submitRequest({data}); console.log(result) })()
ondefetch
esubmitRequest
são funções que retornam promessas.Quando você usa
componentDidMount
semasync
palavra-chave, o documento diz o seguinte:Se você usar
async componentDidMount
, perderá essa capacidade: outra renderização APÓS o navegador atualizar a tela. Porém, se estiver pensando em usar assíncrono, como buscar dados, não é possível evitar que o navegador atualize a tela duas vezes. Em outro mundo, não é possível PAUSAR componentDidMount antes que o navegador atualize a telafonte
Atualizar:
(Minha compilação: Reagir 16, Webpack 4, Babel 7):
Ao usar o Babel 7, você descobrirá:
Usando esse padrão ...
você encontrará o seguinte erro ...
Não detectado ReferenceError: regeneratorRuntime não está definido
Nesse caso, você precisará instalar o babel-plugin-transform-runtime
https://babeljs.io/docs/en/babel-plugin-transform-runtime.html
Se, por algum motivo, você não desejar instalar o pacote acima (babel-plugin-transform-runtime), você deverá seguir o padrão Promise ...
fonte
Eu acho que está tudo bem, desde que você saiba o que está fazendo. Mas pode ser confuso porque
async componentDidMount()
ainda pode estar em execução após acomponentWillUnmount
execução e o componente desmontado.Você também pode iniciar tarefas síncronas e assíncronas
componentDidMount
. SecomponentDidMount
fosse assíncrono, você teria que colocar todo o código síncrono antes do primeiroawait
. Pode não ser óbvio para alguém que o código anterior ao primeiroawait
é executado de forma síncrona. Nesse caso, eu provavelmente continuariacomponentDidMount
síncrono, mas ele chamaria os métodos sync e async.Independentemente de você escolher
async componentDidMount()
os métodos decomponentDidMount()
chamada de sincronização xasync
, é necessário limpar todos os ouvintes ou métodos assíncronos que ainda estejam em execução quando o componente for desmontado.fonte
Na verdade, o carregamento assíncrono no ComponentDidMount é um padrão de design recomendado, pois o React se afasta dos métodos do ciclo de vida herdados (componentWillMount, componentWillReceiveProps, componentWillUpdate) e passa para a renderização assíncrona.
Esta postagem do blog é muito útil para explicar por que isso é seguro e fornecer exemplos para carregamento assíncrono no ComponentDidMount:
https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html
fonte
Eu gosto de usar algo assim
fonte