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 useCallback for 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 useMemo for expensive calculations.
  • Use Zustand selectors to subscribe to slices.
  • Use React.memo for heavy UI components.

Animations

Animations run on the UI thread using react-native-reanimated.

  • Avoid the JS thread for animations.
  • Use Layout Animations for entering/exiting.
  • Use worklets for 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 instance
2const handlePress = useCallback((id: string) => {
3 router.push(`/details/${id}`);
4}, []);
5
6// In renderItem
7<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-image efficiently recycles views.
1import { Image } from '@/components/ui/image';
2
3// Uses our pre-configured wrapper with blurhash & styling support
4<Image
5 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 key props correctly on lists.

Last updated on 2/10/2026

Edit this page on GitHub