Has your Rork-built app ever felt sluggish during device testing? Maybe the list scrolls with a noticeable lag, screen transitions seem stiff, or the app completely freezes after a specific interaction.
While Rork handles code generation automatically, performance tuning still requires hands-on attention. This guide walks you through the most common performance issues in Rork apps — complete with diagnostic steps and practical code examples to fix them.
Symptom Checklist: Which Issue Are You Facing?
Start by identifying which pattern matches your situation.
Jerky or choppy scrolling points to a FlatList or ScrollView issue. Slow or stuttering screen transitions indicate a navigation problem. An app that freezes after pressing a specific button means the main thread is being blocked by heavy processing. A long startup time is an initial rendering issue. An app that gets progressively slower over time suggests a memory leak. Finally, images or videos that load slowly or flicker indicate an image optimization problem.
Issue 1: Jerky or Choppy Scrolling
If your Rork-generated list uses map() inside a ScrollView, performance will degrade noticeably as the data grows. ScrollView renders all child components at once — with 100+ items, lag is inevitable.
Fix: Replace With FlatList
// Heavy implementation — gets choppy as data grows
<ScrollView>
{items.map((item) => (
<ItemCard key={item.id} item={item} />
))}
</ScrollView>
// Lightweight implementation — virtualizes off-screen elements
<FlatList
data={items}
keyExtractor={(item) => item.id.toString()}
renderItem={({ item }) => <ItemCard item={item} />}
initialNumToRender={10}
maxToRenderPerBatch={5}
windowSize={5}
removeClippedSubviews={true}
/>Switching to FlatList resolves scroll jank in the majority of cases.
Optimize the List Item Component
// Prevent unnecessary re-renders of list items
const ItemCard = React.memo(({ item }: { item: Item }) => {
return (
<View style={styles.card}>
<Text style={styles.title}>{item.title}</Text>
<Text style={styles.description}>{item.description}</Text>
</View>
);
});
ItemCard.displayName = 'ItemCard';Issue 2: Slow or Stuttering Screen Transitions
When navigation animations feel sluggish, a heavy initialization process on the destination screen is usually the cause.
Diagnosing the Problem
const HeavyScreen = () => {
const startTime = useRef(Date.now());
useEffect(() => {
const renderTime = Date.now() - startTime.current;
console.log(`[Perf] HeavyScreen render time: ${renderTime}ms`);
if (renderTime > 100) {
console.warn('[Warning] Slow render detected:', renderTime, 'ms');
}
}, []);
return <View>...</View>;
};Fix 1: Lazy Loading
import { lazy, Suspense } from 'react';
const HeavyDetailScreen = lazy(() => import('./HeavyDetailScreen'));
function App() {
return (
<Suspense fallback={<LoadingSpinner />}>
<HeavyDetailScreen />
</Suspense>
);
}Fix 2: Fetch Data After the Screen Appears
const ProductListScreen = () => {
const [products, setProducts] = useState<Product[]>([]);
const [isReady, setIsReady] = useState(false);
useEffect(() => {
const loadProducts = async () => {
try {
const data = await fetchProducts();
setProducts(data);
} catch (error) {
console.error('Failed to fetch products:', error);
} finally {
setIsReady(true);
}
};
loadProducts();
}, []);
if (\!isReady) return <SkeletonLoader />;
return <FlatList data={products} renderItem={({ item }) => <ProductItem item={item} />} />;
};Issue 3: App Freezes After a Specific Action
A momentary freeze after tapping a button means a heavy synchronous operation is blocking JavaScript's main thread.
// Blocking the main thread — causes UI freeze (avoid this)
const handleCalculate = () => {
const result = bigData.map(item => expensiveCalculation(item));
setResult(result);
};
// Release the main thread with async processing (recommended)
const handleCalculate = async () => {
setLoading(true);
await new Promise(resolve => requestAnimationFrame(resolve));
try {
const result = await processInChunks(bigData, 100);
setResult(result);
} finally {
setLoading(false);
}
};
// Utility: process large arrays in batches to avoid blocking
async function processInChunks<T>(data: T[], chunkSize: number): Promise<T[]> {
const results: T[] = [];
for (let i = 0; i < data.length; i += chunkSize) {
results.push(...data.slice(i, i + chunkSize));
// Release the main thread between chunks
await new Promise(resolve => setTimeout(resolve, 0));
}
return results;
}Issue 4: App Takes Too Long to Start
Step 1: Remove Unused Imports
Rork-generated code sometimes includes imports for libraries that are not actually used. Removing them reduces bundle size and speeds up startup.
// Unused imports increase bundle size (avoid)
import { View, Text, TextInput, TouchableOpacity, Modal, Picker, DatePicker } from 'react-native';
// Import only what you use (recommended)
import { View, Text, TextInput, TouchableOpacity } from 'react-native';Step 2: Manage Startup Time With the Splash Screen
import * as SplashScreen from 'expo-splash-screen';
SplashScreen.preventAutoHideAsync();
export default function App() {
const [appReady, setAppReady] = useState(false);
useEffect(() => {
const prepare = async () => {
try {
await Font.loadAsync({ 'CustomFont': require('./assets/fonts/custom.ttf') });
await Asset.loadAsync([require('./assets/images/logo.png')]);
await initializeAppData();
} catch (error) {
console.warn('Startup error:', error);
} finally {
setAppReady(true);
}
};
prepare();
}, []);
const onLayoutRootView = useCallback(async () => {
if (appReady) await SplashScreen.hideAsync();
}, [appReady]);
if (\!appReady) return null;
return (
<View style={{ flex: 1 }} onLayout={onLayoutRootView}>
<Navigation />
</View>
);
}Issue 5: App Gets Slower Over Time (Memory Leak)
Missing cleanup in useEffect is the most common cause of memory leaks in Rork-generated code.
// Memory leak — listeners and timers persist after unmounting (avoid)
useEffect(() => {
const subscription = eventEmitter.addListener('update', handleUpdate);
const timer = setInterval(fetchLatestData, 5000);
}, []);
// Always return a cleanup function (recommended)
useEffect(() => {
const subscription = eventEmitter.addListener('update', handleUpdate);
const timer = setInterval(fetchLatestData, 5000);
return () => {
subscription.remove();
clearInterval(timer);
};
}, []);
// Guard async state updates with an isMounted flag
useEffect(() => {
let isMounted = true;
fetchData().then(data => {
if (isMounted) setData(data);
});
return () => { isMounted = false; };
}, []);Issue 6: Images Load Slowly or Flicker
Switch to expo-image With Caching
import { Image } from 'expo-image';
<Image
source={{ uri: 'https://example.com/product.jpg' }}
style={styles.productImage}
contentFit="cover"
cachePolicy="memory-disk"
placeholder={require('./assets/placeholder.png')}
transition={200}
/>For large local assets, compress them before bundling:
# Compress all PNGs in assets/images while preserving quality
find assets/images -name "*.png" -exec pngquant --force --quality=65-80 {} \;Visualizing Performance With Expo DevTools
npx expo start
# Press 'm' in the terminal to open the Metro UI
# Check the Performance tab for frame rate and memory usageKey metrics: target 60fps (below 30fps is noticeable to users), watch for any JS Thread operations taking more than 80ms, and ensure the UI Thread isn't being blocked.
Looking back
When your Rork app feels sluggish, work through these fixes in order of impact.
For jerky scrolling, replace ScrollView with FlatList and add React.memo to list items — this often delivers an immediate improvement. For freezes, move heavy operations off the main thread using async processing. For slow startup, remove unused imports and use the splash screen to manage perceived load time. For memory leaks, always return cleanup functions from useEffect. For slow images, migrate to expo-image with memory-disk caching.
Performance issues are easy to defer, but they directly affect App Store ratings and user retention. Build a habit of testing on a real physical device before every release.
For general build error troubleshooting, see our Rork App Build Error Complete Guide. To go beyond fixing problems and proactively tune performance, check out Advanced Rork App Performance Optimization.