Erros Comuns de Performance em React Native (E Como Corrigi-los)
Após 8+ anos construindo aplicações React Native, vi os mesmos erros de performance se repetirem em inúmeros projetos. A boa notícia? A maioria desses problemas é fácil de corrigir quando você sabe o que procurar. Neste guia, vou mostrar as armadilhas de performance mais comuns e exatamente como resolvê-las.
1. Re-renders Desnecessários: O Assassino Silencioso de Performance
Este é de longe o erro mais comum que vejo. Toda vez que um componente re-renderiza desnecessariamente, seu app faz trabalho desperdiçado, drenando bateria e causando quedas de frames.
O Problema
// ❌ Ruim: Este componente re-renderiza a cada atualização do pai
const UserCard = ({ user, onPress }) => {
return (
<TouchableOpacity onPress={() => onPress(user.id)}>
<Text>{user.name}</Text>
</TouchableOpacity>
);
};
Cada re-render do pai recria aquela arrow function do onPress, causando re-render do UserCard mesmo quando os dados do usuário não mudaram.
A Solução
// ✅ Bom: Componente memoizado com callbacks estáveis
const UserCard = React.memo(({ user, onPress }) => {
return (
<TouchableOpacity onPress={onPress}>
<Text>{user.name}</Text>
</TouchableOpacity>
);
});
// No componente pai
const handlePress = useCallback((userId) => {
navigation.navigate('UserDetail', { userId });
}, [navigation]);
2. Computações Pesadas na Thread Principal
React Native executa JavaScript em uma única thread. Bloqueie essa thread com computações pesadas, e sua UI congela.
O Problema
// ❌ Ruim: Filtro pesado bloqueia a UI
const SearchResults = ({ data, query }) => {
const filtered = data.filter(item =>
item.title.toLowerCase().includes(query.toLowerCase())
);
return <FlatList data={filtered} .../>;
};
Com 10.000+ itens, esta operação de filtro executa a cada tecla digitada, congelando seu campo de busca.
A Solução
// ✅ Bom: Computação memoizada
const SearchResults = ({ data, query }) => {
const filtered = useMemo(() => {
return data.filter(item =>
item.title.toLowerCase().includes(query.toLowerCase())
);
}, [data, query]);
return <FlatList data={filtered} .../>;
};
Para computações realmente pesadas, considere movê-las para um módulo nativo ou usar bibliotecas como react-native-multithreading.
3. Configuração Incorreta do FlatList
FlatList é poderoso, mas FlatLists mal configurados são uma das principais causas de travamentos no scroll.
Props Críticas que Você Provavelmente Está Esquecendo
// ✅ FlatList Otimizado
<FlatList
data={items}
renderItem={renderItem}
keyExtractor={item => item.id}
// Otimizações de performance
removeClippedSubviews={true}
maxToRenderPerBatch={10}
updateCellsBatchingPeriod={50}
initialNumToRender={10}
windowSize={5}
// Previne thrashing de layout
getItemLayout={(data, index) => ({
length: ITEM_HEIGHT,
offset: ITEM_HEIGHT * index,
index,
})}
/>
O Que Cada Prop Faz
- removeClippedSubviews: Desmonta componentes fora da tela (grande economia de memória)
- maxToRenderPerBatch: Limita renders por evento de scroll (scroll mais suave)
- windowSize: Controla quantas alturas de tela renderizar (balanço entre memória e responsividade)
- getItemLayout: Pula cálculos caros de layout se todos os itens têm a mesma altura
4. Carregamento de Imagens Sem Otimização
Imagens são frequentemente o maior gargalo de performance em apps mobile. Imagens grandes e não otimizadas podem destruir a performance do seu app.
O Problema
// ❌ Ruim: Imagem em resolução total da API
<Image
source={{ uri: 'https://api.example.com/image/4k-photo.jpg' }}
style={{ width: 100, height: 100 }}
/>
Você está baixando uma imagem de 5MB apenas para exibi-la em 100x100 pixels. Desperdício!
A Solução
// ✅ Bom: Use FastImage com dimensionamento adequado
import FastImage from 'react-native-fast-image';
<FastImage
source={{
uri: 'https://api.example.com/image/thumbnail-100.jpg',
priority: FastImage.priority.normal,
}}
style={{ width: 100, height: 100 }}
resizeMode={FastImage.resizeMode.cover}
/>
Melhores práticas:
- Use
react-native-fast-imagepara melhor cache e performance - Solicite imagens no tamanho apropriado da sua API
- Use formato WebP (80% menor que PNG)
- Implemente carregamento progressivo de imagens para imagens grandes
5. Problemas de Performance na Navegação
Transições de tela devem ser suaves e instantâneas. Se não são, você provavelmente está cometendo um destes erros.
Carregamento Lazy de Telas Pesadas
// ✅ Bom: Lazy load de imports pesados
const HeavyScreen = lazy(() => import('./screens/HeavyScreen'));
const Stack = createNativeStackNavigator();
function AppNavigator() {
return (
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Heavy" component={HeavyScreen} />
</Stack.Navigator>
);
}
Evite Trabalho Durante a Navegação
// ❌ Ruim: Operação pesada bloqueia navegação
navigation.navigate('Details');
performHeavyOperation();
// ✅ Bom: Adie trabalho pesado
navigation.navigate('Details');
requestAnimationFrame(() => {
performHeavyOperation();
});
6. Console.log em Produção
Isso parece trivial, mas deixar console.logs em produção pode deixar seu app 30-40% mais lento.
A Solução
// No seu arquivo de entrada (index.js)
if (!__DEV__) {
console.log = () => {};
console.warn = () => {};
console.error = () => {};
}
Ou use uma biblioteca de logging adequada como react-native-logs que desabilita automaticamente em produção.
Impacto Real: Um Estudo de Caso
Em um projeto recente, aplicamos estas otimizações a um app de e-commerce com 50.000+ produtos:
- Antes: 28 FPS em média, 3.2s de tempo de transição de tela
- Depois: 58 FPS em média, 0.4s de tempo de transição de tela
- Resultado: 2x de melhoria no engajamento do usuário, 40% de redução em crashes
Medindo Performance
Você não pode melhorar o que não mede. Use estas ferramentas para acompanhar seu progresso:
- Flipper: React DevTools, Inspetor de Rede, Monitor de Performance
- React Native Performance Monitor: Contador de FPS integrado (chacoalhe o dispositivo → Show Perf Monitor)
- Xcode Instruments / Android Profiler: Análise profunda de performance nativa
Conclusão
Problemas de performance em React Native são quase sempre corrigíveis. A chave é saber o que procurar e aplicar as otimizações certas sistematicamente. Comece com as vitórias fáceis (remover console.logs, memoizar componentes) e avance para otimizações mais avançadas.
Lembre-se: 60 FPS deve ser seu baseline, não seu objetivo. Usuários esperam apps suaves, com sensação nativa, e estas otimizações vão te levar até lá.