Performance Optimization
Techniques and best practices for keeping your Twinbloc app running smoothly at 60fps (or 120fps).
List Performance
We use Shopify's FlashList instead of FlatList. It recycles components to achieve up to 5x better performance on the UI thread.
- Always provide
estimatedItemSize. - Use
useCallbackfor item event handlers. - Avoid inline objects/arrays in
renderItem.
Computation & State
Heavy computations are memoized, and state updates are optimized to prevent unnecessary re-renders.
- Use
useMemofor expensive calculations. - Use Zustand selectors to subscribe to slices.
- Use
React.memofor heavy UI components.
Animations
Animations run on the UI thread using react-native-reanimated.
- Avoid the JS thread for animations.
- Use
Layout Animationsfor entering/exiting. - Use
workletsfor synchronous UI logic.
Storage
We use MMKV for synchronous, high-performance storage.
- ~30x faster than AsyncStorage.
- Fully synchronous calls.
- Encrypted storage support.
List Optimization Deep Dive
Rendering long lists is one of the most resource-intensive tasks in mobile apps. Here is how to ensure your lists stay buttery smooth.
1. Hoist Callbacks
Avoid creating new functions inside renderItem. Instead, create a single handler in the parent and pass it down.
1// ✅ Correct: Single handler instance2const handlePress = useCallback((id: string) => {3 router.push(`/details/${id}`);4}, []);56// In renderItem7<ListItem onPress={handlePress} id={item.id} />
2. Memoize List Items
Wrap your list item components in React.memo to prevent re-renders when other items change.
1const ListItem = React.memo(({ item, onPress }: Props) => {2 return (3 <Pressable onPress={() => onPress(item.id)} className="p-4">4 <Text>{item.title}</Text>5 </Pressable>6 );7}, (prev, next) => prev.item.id === next.item.id); // Optional custom comparison
Image Optimization
Images are often the biggest bottleneck. Twinbloc uses a custom wrapper around expo-image located atsrc/components/ui/image.tsx.
- Memory Caching: Images are cached in memory and on disk automatically.
- BlurHash: A blurred placeholder is shown instantly while the full image loads.
- Recycling: When used in lists,
expo-imageefficiently recycles views.
1import { Image } from '@/components/ui/image';23// Uses our pre-configured wrapper with blurhash & styling support4<Image5 source="https://example.com/large-photo.jpg"6 placeholder="LGF5]+Yk^6#M@-5c,1J5@[or[Q6."7 contentFit="cover"8 className="w-full h-48 rounded-xl"9/>
Tip: You can also use the preloadImages utility exported from the same file to eagerly load critical images (like hero headers).
Bundle & Architecture
Hermes Engine
Enabled by default. Hermes is a JavaScript engine optimized for running React Native. It provides improved start-up time, decreased memory usage, and smaller app size.
Structure & Imports
We use barrelling (index files) for cleaner imports, but be mindful of circular dependencies. The Metro bundler is configured to handle large codebases efficiently.
React Compiler (Experimental)
Twinbloc is prepared for the upcoming React Compiler. We follow strict rules of hooks and avoid side effects in render to ensure future compatibility for automatic memoization.
Current Best Practices
- Don't mutate state directly.
- Keep components pure.
- Destructure props/state early.
- Use
keyprops correctly on lists.
Last updated on 2/10/2026
Edit this page on GitHub