From harness-claude
Optimizes React Native app performance with Hermes engine, memoization, lazy loading, image optimization, and profiling tools.
How this skill is triggered — by the user, by Claude, or both
Slash command
/harness-claude:mobile-performance-patternsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> Optimize React Native app performance with profiling, memoization, lazy loading, and native thread management
Optimize React Native app performance with profiling, memoization, lazy loading, and native thread management
// app.json
{
"expo": {
"jsEngine": "hermes"
}
}
React.memo, useMemo, and useCallback.// Memoize components that receive the same props frequently
const ProductCard = memo(function ProductCard({ product }: { product: Product }) {
return (
<View>
<Image source={{ uri: product.imageUrl }} style={styles.image} />
<Text>{product.name}</Text>
<Text>${product.price}</Text>
</View>
);
});
// Memoize expensive computations
function OrderList({ orders, filter }: Props) {
const filteredOrders = useMemo(
() => orders.filter((o) => o.status === filter).sort((a, b) => b.date - a.date),
[orders, filter]
);
// Stable callback reference for child components
const handlePress = useCallback(
(orderId: string) => {
navigation.navigate('OrderDetail', { orderId });
},
[navigation]
);
return <FlatList data={filteredOrders} renderItem={/* ... */} />;
}
useCallback for FlatList renderItem and keyExtractor.const renderItem = useCallback(
({ item }: { item: Order }) => <OrderCard order={item} onPress={handlePress} />,
[handlePress]
);
const keyExtractor = useCallback((item: Order) => item.id, []);
<FlatList data={orders} renderItem={renderItem} keyExtractor={keyExtractor} />;
import { lazy, Suspense } from 'react';
const HeavyChart = lazy(() => import('./components/HeavyChart'));
function Dashboard() {
return (
<Suspense fallback={<ChartSkeleton />}>
<HeavyChart data={chartData} />
</Suspense>
);
}
import { Image } from 'expo-image';
// expo-image provides caching, blurhash placeholders, and memory management
<Image
source={{ uri: product.imageUrl }}
placeholder={{ blurhash: product.blurhash }}
contentFit="cover"
transition={200}
style={styles.image}
recyclingKey={product.id}
/>;
expo-image instead of React Native's Image for better caching# Enable the React DevTools profiler
npx react-devtools
// Bad — imports the entire library
import { format, parse, addDays, subDays, isAfter } from 'date-fns';
// Good — import only what you need (tree-shakeable)
import format from 'date-fns/format';
import addDays from 'date-fns/addDays';
// Check bundle size
npx expo-doctor --check-dependencies
expo-splash-screen to keep the splash visible until critical data loadsexpo-font and expo-assetimport * as SplashScreen from 'expo-splash-screen';
SplashScreen.preventAutoHideAsync();
function App() {
const [ready, setReady] = useState(false);
useEffect(() => {
async function prepare() {
await loadFonts();
await loadCriticalData();
setReady(true);
}
prepare();
}, []);
const onLayoutRootView = useCallback(async () => {
if (ready) await SplashScreen.hideAsync();
}, [ready]);
if (!ready) return null;
return <View onLayout={onLayoutRootView}>{/* app content */}</View>;
}
Avoid bridge traffic for animations. Use Reanimated (UI thread) instead of Animated (JS thread). Use useAnimatedStyle instead of style objects that depend on animated values.
Monitor performance in production with tools like Sentry Performance or custom metrics.
React Native threading model: React Native has three threads — the JS thread (runs your React code), the UI/Main thread (renders native views), and the Shadow thread (calculates layout with Yoga). Performance problems usually fall into: JS thread overload (expensive re-renders), bridge congestion (too much data crossing), or main thread blocking (synchronous native calls).
Common re-render causes:
memo)useMemo)useCallback)Memory management:
useEffect returnNew Architecture (Fabric + TurboModules): The new architecture removes the bridge, enabling synchronous communication between JS and native. It improves performance for interop-heavy operations. Available in Expo SDK 51+.
https://reactnative.dev/docs/performance
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeOptimizes React Native apps with guidelines for FPS, TTI, bundle size, memory leaks, re-renders, and animations. Helps with Hermes, JS thread blocking, FlashList, native modules, and frame drops.
Provides React Native performance optimization guidelines for FPS, TTI, bundle size, memory leaks, re-renders, and animations. Guides Hermes optimization, JS thread blocking, bridge overhead, FlashList, native modules, and jank debugging.
Optimizes React Native app performance via FlatList tweaks, React.memo/useMemo, FastImage caching, bundle size reduction, and profiling techniques.