Já lancei algumas apps em React Native. Em todas elas, a determinada altura do desenvolvimento, a app começou a parecer lenta. O scroll ficava a gaguejar. As transições travavam. O thread da UI simplesmente não conseguia acompanhar. E em todas as vezes, a causa raiz resumia-se a um conjunto pequeno de erros evitáveis.
Este não é um guia exaustivo sobre os internos do React Native. É um resumo prático dos padrões que realmente fizeram diferença quando estava a depurar performance em apps reais.
Parar de Re-renderizar Tudo
O problema de performance mais comum que vejo em React Native são re-renderizações desnecessárias. Um componente pai atualiza o seu estado e, de repente, dezenas de componentes filhos re-renderizam mesmo que nada relevante para eles tenha mudado.
A solução é geralmente simples. Envolve componentes caros de renderizar com React.memo. Move o estado o mais perto possível de onde é usado. Usa useCallback para funções passadas como props a filhos memorizados, e useMemo para valores computados dispendiosos.
Uma coisa a ter em atenção: literais de objetos e arrays em linha no JSX. Escrever style={{ flex: 1 }} cria um novo objeto a cada renderização. Move os estilos para chamadas StyleSheet.create fora do componente, ou pelo menos para uma variável definida fora do caminho de renderização.
FlatList é a Tua Aliada, se a Usares Corretamente
Se estás a renderizar uma lista longa e está lenta, a primeira pergunta é se estás sequer a usar FlatList. Fazer map sobre um array dentro de um ScrollView renderiza todos os itens de uma vez. Para cinco itens está bem. Para duzentos é um desastre.
Mas a FlatList sozinha não chega. Tens de a ajudar. Define removeClippedSubviews como true. Ajusta initialNumToRender, maxToRenderPerBatch e windowSize com base na altura dos itens e no comprimento da lista. Se os teus itens têm altura fixa, passa getItemLayout para que a FlatList possa saltar medições por completo.
Certifica-te também de que o teu renderItem está memorizado. Se a referência da função mudar a cada renderização, a FlatList vai re-renderizar todos os itens visíveis mesmo quando os dados não mudaram.
As Imagens Vão Destruir a Taxa de Frames
As imagens são uma das fontes de lentidão mais ignoradas. Descodificar um JPEG grande no thread principal durante o scroll é suficiente para perder frames de forma notável.
Algumas coisas que ajudam: redimensiona as imagens no servidor antes de as servir (não mandes uma imagem 4K para um ecrã de telemóvel que a renderiza a 100px). Usa uma biblioteca de cache como react-native-fast-image em vez do componente Image nativo, que gere cache e prioridade de fila muito melhor. Se tens muitas imagens numa lista, define a prop priority para que as imagens fora do ecrã não compitam com as visíveis.
Move o Trabalho Para Fora do Thread JS
O React Native corre o teu JavaScript numa única thread. Se estás a fazer computação pesada aí, estás a competir com renderização, gestão de eventos e animações ao mesmo tempo.
Para animações, para de usar a API Animated com useNativeDriver: false. Quase todas as animações podem correr na thread nativa com useNativeDriver: true. Se os requisitos de animação forem além do que o Animated suporta, olha para o Reanimated 3. Permite escrever lógica de animação em worklets que correm diretamente na thread de UI, sem qualquer overhead de JS.
Para trabalho intensivo de CPU como parsing, ordenação de grandes conjuntos de dados ou processamento de imagens, considera mover para uma thread de fundo usando uma biblioteca como react-native-threads ou chamando código nativo via um módulo JSI.
Faz Profiling Antes de Otimizar
A pior coisa que podes fazer é adivinhar. Passei uma tarde a memorizar componentes que não eram o bottleneck, enquanto um único item de lista dispendioso estava a fazer cada evento de scroll demorar 40ms.
Usa o React DevTools Profiler para ver quais componentes estão a re-renderizar e quanto tempo demoram. Usa o Flipper com o plugin de Performance para ver os tempos de frame das threads JS e UI lado a lado. No Android, ativa o overlay de FPS no dispositivo nas definições de programador.
Com dados em mão, corrige primeiro os maiores problemas. Uma renderização de 50ms num componente chamado uma vez no arranque importa muito menos do que uma renderização de 5ms num item de lista que corre sessenta vezes por scroll.
Pequenas Coisas Que Somam
Para além dos grandes padrões, há um conjunto de pequenos hábitos que consistentemente ajudam. Usa o Hermes como motor de JS, é mais rápido no arranque e usa menos memória do que o JSC. Ativa a Nova Arquitetura se as tuas dependências a suportarem; o novo renderer e as funcionalidades concorrentes fazem uma diferença real. Mantém o tamanho do bundle reduzido auditando dependências com react-native-bundle-visualizer e removendo tudo o que não estás realmente a usar.
Nada disto é magia. A performance vem de perceber onde o tempo está realmente a ser gasto e corrigir os piores problemas um a um. Os padrões acima são apenas os lugares onde quase sempre encontro os problemas.



