O React Native expõe uma API chamada Animated. Consiste em muitas coisas maravilhosas, como valores de animação, animações de primavera / cronometragem e eventos. Mas não estamos aqui para discutir a API, deixarei isso para o documentos oficiais e meu Lista de reprodução do YouTube. Eles fazem um trabalho muito melhor cobrindo isso para você.
O que queremos discutir aqui é, de fato, como o React Native anima as coisas na tela e o que está por trás do capô.
Nós todos sabemos isso Como o React Native funciona sob o capô do meu outro artigo. (Leia rapidamente se não tiver). Como o React Native usa o React e o JavaScript, existem precisamente duas maneiras pelas quais as animações na tela podem ser realizadas. Primeiro de tudo, vamos esclarecer um fato. O React Native constrói visualizações nativas reais na tela, e não as renderizadas por meio de um navegador da Web incorporado, como o Ionic. Por esse motivo, se você deseja animar uma exibição de alguma forma, isso deve ser feito na exibição nativa. O JavaScript precisa se comunicar de alguma forma com o sistema operacional que a exibição precisa ser atualizada. O JavaScript é executado em um segmento diferente do segmento da interface do usuário (segmento principal), e somente esse segmento da interface do usuário pode atualizar as visualizações. Portanto, o JS precisa usar a ponte que o React Native fornece para serializar e comunicar esses dados ao SO.
Trabalhe em JS e atualize a visualização nativa
Essa abordagem significa que você tem uma visão que já está visível na tela do usuário e trabalha no que precisa ser feito para sua próxima posição no encadeamento JavaScript. As etapas são mais ou menos assim:
- Animação começa
- O JavaScript é executado
requestAnimationFrame
função - uma função que tentativas para executar a 60 chamadas / segundo (60 FPS) - JavaScript calcula a próxima posição / opacidade / transformação / o que você estiver animando na exibição.
- JavaScript serializa esse valor e o envia pela ponte.
- No outro extremo da ponte, Java (Android) ou Objective C (iOS) desserializa esse valor e aplica as transformações fornecidas na exibição mencionada.
- O quadro é atualizado na tela.
Você viu o que aconteceu lá? Não havia nenhuma etapa envolvida na qual renderizamos novamente um componente React Native. Isso significa que, na verdade, a API animada "ignora" a filosofia do React de não alterar variáveis de "estado". Isso é realmente útil no caso de animações, porque será muito lento e com desempenho ruim se permitirmos que o React renderize novamente um componente 60 vezes por segundo!
Parece tudo bom e bom, mas há um problema muito fundamental aqui. O JavaScript é único e a natureza assíncrona do JavaScript não funciona aqui porque as animações são tarefas vinculadas à CPU. Vamos dar uma olhada nos prós e contras dessa abordagem:
Prós
- Você pode ter animações muito sofisticadas escritas em JS e visíveis como animações nativas.
- Mais controle sobre o estado da animação
Contras
- Grande penalidade de desempenho se o seu segmento JavaScript estiver super ocupado.
- Bridge está ocupado, desempenho reduzido OS / JS quer se comunicar.
Esse golpe é um grande golpe para ser honesto. Há um vídeo mais adiante no artigo, que realmente mostraria isso em tempo real, e como JS estraga muito as animações quando o encadeamento JavaScript fica ocupado.
Por que as animações JS ficam atrasadas?
As animações feitas por JS começam a ficar lentas quando a animação está em andamento e o usuário (ou aplicativo) solicita alguma outra ação que deve ser tratada pelo encadeamento JS. Por exemplo, considere uma animação em andamento. Isso significa que JS está ocupado executando o requestAnimationFrame
função. Supondo que as atualizações não sejam muito pesadas, vamos supor que agora o usuário comece a tocar em um botão na tela que incrementa um contador. Agora, o que está acontecendo é com o requestAnimationFrame
sendo chamada com frequência, sua árvore virtual do React também é re-renderizada repetidamente para contabilizar o aumento do contador. Ambos são tarefas vinculadas à CPU em execução em um único encadeamento; portanto, haveria um impacto no desempenho. requestAnimationFrame
começaria a soltar quadros por causa do trabalho adicional sendo realizado pelo encadeamento JS e você obterá uma animação muito instável.
Animações de driver nativo
Não se preocupe, porque o React Native realmente permite que você execute animações no driver nativo também! O que quero dizer com isso? Você pode perguntar. Bem, simplificando, isso significa que o React Native descarrega o trabalho de animação do encadeamento JS para o encadeamento da UI (o SO) e permite que ele lide com a animação do objeto. Isso tem alguns benefícios:
- O encadeamento JS (e a ponte React Native) agora está livre para lidar com outras tarefas intensivas - como toques repetitivos do usuário.
- As animações são muito mais suaves por causa de nenhuma sobrecarga de serialização / desserialização e comunicação de ponte.
Como o React Native consegue isso? Para isso, o que o pessoal do React Native fez é permitir que você, como desenvolvedor, forneça uma propriedade chamada useNativeDriver
como um valor booleano quando você está construindo um objeto de animação. Quando definido como verdadeiro, o React Native, antes de iniciar a animação, serializava todo o estado da animação e o que precisa ser feito no futuro e o transferia uma vez pela ponte para o sistema operacional. A partir de então, o código Java (Android) ou Objective C (iOS) executaria as animações em vez do JavaScript calcular o próximo quadro de animação e enviar esses dados repetidamente pela ponte.
Isso acelera bastante as animações e as animações seriam muito mais suaves, especialmente em dispositivos de gama baixa. Vamos ver uma demonstração em vídeo de animações nativas baseadas em animações v / S JS no React Native:
Nesse caso, as etapas são mais ou menos assim:
- Animação começa
- JS serializa as informações da animação e as envia pela ponte.
- No outro extremo, o sistema operacional recebe essas informações e executa a animação nativamente.
É isso aí! Muito mais leve para o encadeamento JS agora. Não mais requestAnimationFrame
corrida.
No entanto, ele tem sua própria parcela de prós e contras.
Prós:
- Animações mais rápidas
- Encadeamento JS sem bloqueio
- Ponte menos inchada
Contras:
- Menos controle sobre as animações (o JS não consegue ver o que está acontecendo na tela depois que a animação “automática” é iniciada)
- Menos propriedades para manipular – o driver nativo não suporta todas as propriedades a serem animadas, como
width
ouheight
não é nativamente animado, masopacity
etransform
é.
Em muitos casos, você descobrirá que pode solucionar um conjunto diferente de animações usando o useNativeDriver: true
para criar um efeito semelhante que não pode ser alcançado sem definir useNativeDriver: false
. A equipe do React Native está trabalhando para adicionar suporte a mais propriedades enquanto falamos, mas por enquanto, acredito que seja ótimo no momento.
Conclusão
Este artigo mostrou como as animações do React Native realmente funcionam sob o capô e por que é bonito. O que você acha deste artigo? Diga-me conectando comigo no meu Instagram e Twitter contas! Novo no React Native? Comece a aprender codedamn – uma plataforma para os desenvolvedores aprenderem e se conectarem!
Paz!