Debugging React Native Like a Pro
Advanced debugging techniques for React Native apps, from Flipper to native debugging and performance profiling.
console.log debugging only gets you so far. Here are the tools and techniques I use for serious debugging.
1. Flipper
Flipper is the official debugging tool for React Native. Install it and enable in your app:
// ios/Podfile
use_flipper!()
// android/app/build.gradle debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}")
Key Flipper Features:
Network Inspector See every network request, including headers and response bodies. Filter by status code to find failed requests.
React DevTools Inspect component hierarchy, props, and state directly in Flipper.
Layout Inspector Visual debugging for layout issues. Highlights component bounds and shows style properties.
Databases Inspect AsyncStorage, SQLite, and other local databases.
2. React Native Debugger
A standalone app combining React DevTools and Redux DevTools:
brew install react-native-debugger
Enable remote debugging (shake device → Debug) and the debugger auto-connects.
Redux DevTools Features:
- Time-travel debugging
- Action replay
- State diff between actions
3. Native Debugging
Sometimes bugs are in native code. You need Xcode/Android Studio.
iOS (Xcode):
ios/YourApp.xcworkspaceyarn ios)Android (Android Studio):
android/ folderViewing Native Logs:
# iOS
xcrun simctl spawn booted log stream --level debug | grep YourApp
# Android adb logcat *:S ReactNative:V ReactNativeJS:V
4. Performance Profiling
JS Performance:
Enable the Performance Monitor (shake → Perf Monitor) and watch:
- JS FPS (should be 60)
- UI FPS (should be 60)
- RAM usage
Use React's Profiler:
import { Profiler } from 'react';
function onRenderCallback( id, phase, actualDuration, baseDuration, startTime, commitTime ) { console.log(${id} rendered in ${actualDuration}ms); }
<Profiler id="MyComponent" onRender={onRenderCallback}> <MyComponent /> </Profiler>
Systrace (Android):
# Start trace
yarn react-native start --reset-cache
# In another terminal adb shell "echo 0 > /sys/kernel/debug/tracing/tracing_on" adb shell "echo 1 > /sys/kernel/debug/tracing/tracing_on"
# Reproduce the issue, then: adb shell "echo 0 > /sys/kernel/debug/tracing/tracing_on" adb pull /sys/kernel/debug/tracing/trace ./trace.txt
5. Crash Debugging
JavaScript Crashes:
Use error boundaries:
class ErrorBoundary extends React.Component {
state = { hasError: false, error: null };
static getDerivedStateFromError(error) { return { hasError: true, error }; }
componentDidCatch(error, errorInfo) { // Log to crash reporting service crashlytics().recordError(error); console.log('Error caught:', error, errorInfo); }
render() { if (this.state.hasError) { return <ErrorFallback error={this.state.error} />; } return this.props.children; } }
Native Crashes:
For iOS, check crash logs:
- Xcode → Window → Devices and Simulators → View Device Logs
adb logcat -b crash
Use Sentry or Crashlytics for production crash reporting.
6. Common Issues & Solutions
"Red Box" Errors: Read the stack trace carefully. The actual error is usually in the first few lines.
Infinite Re-renders: Add logging to useEffect:
useEffect(() => { console.log('Effect triggered, deps:', dep1, dep2); }, [dep1, dep2]);
Memory Leaks: Use Flipper's memory graph or React DevTools to find components that don't unmount.
Network Issues: Check if the device can reach your API. Common issue: localhost doesn't work on physical devices.
// Use your machine's IP instead
const API_URL = __DEV__
? 'http://192.168.1.100:3000'
: 'https://api.production.com';
Debugging is a skill. The more you practice with these tools, the faster you'll find bugs.