Rendimiento en React Native
El rendimiento es crucial para apps moviles. Aqui estan las tecnicas clave para mantener tu app rapida y fluida.
Optimizacion de Listas
import { FlatList, memo } from 'react';
// Componente de item memorizado
const Item = memo(({ titulo, onPress }) => (
<TouchableOpacity onPress={onPress}>
<Text>{titulo}</Text>
</TouchableOpacity>
));
function ListaOptimizada({ datos }) {
// Memoizar renderItem
const renderItem = useCallback(({ item }) => (
<Item
titulo={item.titulo}
onPress={() => console.log(item.id)}
/>
), []);
// Memoizar keyExtractor
const keyExtractor = useCallback((item) => item.id.toString(), []);
return (
<FlatList
data={datos}
renderItem={renderItem}
keyExtractor={keyExtractor}
// Optimizaciones
removeClippedSubviews={true}
maxToRenderPerBatch={10}
windowSize={5}
initialNumToRender={10}
getItemLayout={(data, index) => ({
length: 80, // altura fija del item
offset: 80 * index,
index,
})}
/>
);
}
Memorizacion de Componentes
import { memo, useMemo, useCallback } from 'react';
// memo para componentes
const ComponenteCostoso = memo(function ComponenteCostoso({ datos }) {
// Solo se re-renderiza si datos cambia
return <View>{/* contenido */}</View>
});
// useMemo para calculos costosos
function ComponenteConCalculo({ items }) {
const itemsProcesados = useMemo(() => {
return items.filter(i => i.activo).sort((a, b) => a.orden - b.orden);
}, [items]);
return <FlatList data={itemsProcesados} />;
}
// useCallback para funciones
function Padre() {
const [cuenta, setCuenta] = useState(0);
const handlePress = useCallback(() => {
setCuenta(c => c + 1);
}, []);
return <Hijo onPress={handlePress} />;
}
Optimizacion de Imagenes
import { Image } from 'react-native';
import FastImage from 'react-native-fast-image';
// Imagen basica con cache
<Image
source={{ uri: 'https://ejemplo.com/imagen.jpg' }}
style={{ width: 200, height: 200 }}
resizeMode="cover"
/>
// FastImage (mejor rendimiento y cache)
<FastImage
source={{
uri: 'https://ejemplo.com/imagen.jpg',
priority: FastImage.priority.high,
cache: FastImage.cacheControl.immutable,
}}
style={{ width: 200, height: 200 }}
resizeMode={FastImage.resizeMode.cover}
/>
// Consejos:
// - Usa imagenes del tamano correcto
// - Comprime imagenes antes de subirlas
// - Usa formato WebP cuando sea posible
// - Implementa placeholder mientras carga
Animaciones Optimizadas
import { Animated, useRef } from 'react';
import Reanimated, {
useSharedValue,
withSpring,
useAnimatedStyle
} from 'react-native-reanimated';
// Con Animated (JS thread)
function AnimacionBasica() {
const fadeAnim = useRef(new Animated.Value(0)).current;
useEffect(() => {
Animated.timing(fadeAnim, {
toValue: 1,
duration: 500,
useNativeDriver: true, // Importante!
}).start();
}, []);
return (
<Animated.View style={{ opacity: fadeAnim }}>
<Text>Fade In</Text>
</Animated.View>
);
}
// Con Reanimated (UI thread - mejor rendimiento)
function AnimacionReanimated() {
const offset = useSharedValue(0);
const animatedStyles = useAnimatedStyle(() => ({
transform: [{ translateX: withSpring(offset.value) }],
}));
return (
<Reanimated.View style={animatedStyles}>
<Text>Animado</Text>
</Reanimated.View>
);
}
Evitar Re-renders Innecesarios
// MAL - crea nuevo objeto en cada render
<View style={{ flex: 1, padding: 10 }}>
// BIEN - estilos fuera del componente
const styles = StyleSheet.create({
contenedor: { flex: 1, padding: 10 }
});
<View style={styles.contenedor}>
// MAL - funcion inline crea nueva referencia
<Button onPress={() => handlePress(id)} />
// BIEN - useCallback
const onPress = useCallback(() => handlePress(id), [id]);
<Button onPress={onPress} />
// MAL - objeto nuevo cada render
<Componente datos={{ nombre: 'Ana' }} />
// BIEN - memoizar
const datos = useMemo(() => ({ nombre: 'Ana' }), []);
Herramientas de Depuracion
// React DevTools
// Instala la extension de navegador o standalone
// Flipper (depurador de escritorio)
// https://fbflipper.com
// Performance Monitor (en desarrollo)
// Agitar dispositivo -> "Show Perf Monitor"
// Console para medir tiempo
console.time('operacion');
// ... codigo
console.timeEnd('operacion');
// React.Profiler
<Profiler id="MiComponente" onRender={onRenderCallback}>
<MiComponente />
</Profiler>
Lista de Verificacion de Rendimiento
- Usa
FlatListen lugar deScrollViewpara listas - Memoriza componentes pesados con
memo - Siempre usa
useNativeDriver: trueen animaciones - Optimiza imagenes (tamano, formato, cache)
- Evita crear funciones/objetos inline en render
- Usa React DevTools Profiler para identificar problemas
- Mantener 60 FPS - monitorear con Performance Monitor