Skip to main content

Handling Errors and Crashes

1. Using Error Boundaries

Property Description Usage
ErrorBoundary Component that catches JavaScript errors anywhere in its child component tree class ErrorBoundary extends React.Component { ... }
componentDidCatch Method called when an error is caught componentDidCatch(error, errorInfo)
fallback Rendered when an error occurs <ErrorBoundary fallback="<h1>Something went wrong</h1>">

Example: Basic Error Boundary

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  componentDidCatch(error, errorInfo) {
    console.error("Caught an error:", error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      return <h1>Something went wrong.</h1>;
    }

    return this.props.children;
  }
}
Note: Error boundaries only catch errors in the component tree below them. They do not catch errors in event handlers or asynchronous code like setTimeouts.

2. Implementing Global Error Handlers

Example: Setting up a global error handler

import { ErrorBoundary } from 'react-native-error-boundary';

const App = () => {
  return (
    <ErrorBoundary
      onError={(error, errorInfo) => {
        console.error('Global Error:', error);
        console.error('Error Info:', errorInfo);
      }}
    >
      <MyApp />
    </ErrorBoundary>
  );
};
Handler Type Description Usage
ErrorBoundary Component that catches JavaScript errors below it in the tree Wrap root or major sections of your app
onError Callback function when an error is caught Log errors or send to crash reporting service
Note: Error boundaries only catch errors in the rendering phase, lifecycle methods, and constructors of child components.

Example: Logging errors to a service

const logErrorToService = (error, errorInfo) => {
  fetch('https://api.example.com/errors', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      error: error.toString(),
      stack: error.stack,
      componentStack: errorInfo.componentStack,
    }),
  });
};

const App = () => {
  return (
    <ErrorBoundary onError={logErrorToService}>
      <MyApp />
    </ErrorBoundary>
  );
};

3. Catching Promise Rejections

Method Description Usage
Promise.catch() Catches rejection reason of a Promise promise.catch((error) => { ... });
try/catch with async/await Handles asynchronous errors in a structured way
try {
  const result = await asyncFunction();
} catch (error) {
  console.error('Error:', error);
}

Example: Handling Promise Rejection

const fetchData = () => {
  return fetch('/api/data')
    .then(response => {
      if (!response.ok) throw new Error('Network error');
      return response.json();
    })
    .catch(error => {
      console.error('Fetch failed:', error);
      return null;
    });
};

4. Logging Errors to Services

Service Features Notes
Sentry captureException, captureMessage Full error tracking, breadcrumbs, performance monitoring
Bugsnag notify, leaveBreadcrumb Real-time error tracking, crash reporting, dashboard
LogRocket sessionURL, replayURL Session replay, error tracking, user behavior analytics
Rollbar reportException, reportMessage Real-time error tracking, deployment tracking, user impact

Example: Sentry Integration

import * as Sentry from '@sentry/react-native';

Sentry.init({
  dsn: 'YOUR_DSN_HERE',
});

// Log an exception
try {
  throw new Error('Something went wrong');
} catch (error) {
  Sentry.captureException(error);
}

Example: Bugsnag Integration

import Bugsnag from '@bugsnag/react-native';

Bugsnag.start({
  apiKey: 'YOUR_API_KEY'
});

// Notify Bugsnag of an error
Bugsnag.notify(new Error('Something went wrong'));
Note: Ensure that sensitive data is not sent to error logging services. Use beforeSend hooks or filtering to sanitize logs.

5. Handling Native Crashes

Crash Type Description Handling Strategy Tools
JavaScript Exceptions Uncaught JavaScript errors in React Native Use try/catch blocks and Errors for graceful handling errorBoundary, console.error
Native Crashes (iOS/Android) Crashes in native code (e.g., memory issues, unhandled exceptions) Implement crash reporting and recovery logic using native crash handlers Crashlytics, Bugsnag, Sentry
Memory Leaks Improper memory management causing app instability Monitor memory usage with tools like Flipper or React Native Debugger Flipper, React DevTools

Example: Implementing Error Boundaries in React Native

import React from 'react';<br><br>class ErrorBoundary extends React.Component {<br>&nbsp;&nbsp;constructor(props) {<br>&nbsp;&nbsp;&nbsp;&nbsp;super(props);<br>&nbsp;&nbsp;&nbsp;&nbsp;this.state = { hasError: false };<br>&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;static getDerivedStateFromError(error) {<br>&nbsp;&nbsp;&nbsp;&nbsp;// Update state so the next render will show the fallback UI.<br>&nbsp;&nbsp;&nbsp;&nbsp;return { hasError: true };<br>&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;componentDidCatch(error, errorInfo) {<br>&nbsp;&nbsp;&nbsp;&nbsp;// You can also log the error to an error reporting service<br>&nbsp;&nbsp;&nbsp;&nbsp;console.error("Error caught by boundary:", error, errorInfo);<br>&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;render() {<br>&nbsp;&nbsp;&nbsp;&nbsp;if (this.state.hasError) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// You can render any fallback UI<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return <h1>Something went wrong.</h1>;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;return this.props.children;<br>&nbsp;&nbsp;}<br>}<br><br>export default ErrorBoundary;
Note: Error boundaries in React Native only catch errors in the component tree below them. They do not catch errors in event handlers or asynchronous code like setTimeout or requestAnimationFrame.

Example: Using Sentry for Native Crash Reporting

import * as Sentry from '@sentry/react-native';<br><br>Sentry.init({<br>&nbsp;&nbsp;dsn: 'YOUR_DSN_HERE',<br>&nbsp;&nbsp;enableAutoSessionTracking: true,<br>});<br><br>// In your app entry point<br>Sentry.captureException(new Error('Native crash example'));

Native Crash Handling Summary

  • Use ErrorBoundary for JavaScript errors
  • Integrate crash reporting tools like Sentry or Bugsnag for native crashes
  • Monitor memory usage to prevent leaks
  • Implement proper logging and error tracking

6. Using Try-Catch Blocks

Feature Description Usage
try...catch Standard JavaScript error handling mechanism Wrap code that might throw an error in a try block and handle it in catch
Error object Represents an error with properties like name, message, and stack Access error details in the catch block

Example: Basic Try-Catch Usage

try {
  const result = JSON.parse(invalidJson);
} catch (error) {
  console.error("Parsing failed:", error.message);
}

Example: Handling Asynchronous Errors

try {
  const response = await fetch("https://api.example.com/data");
  const data = await response.json();
} catch (error) {
  console.error("Network error:", error.message);
}

7. Implementing Crash Reporting

Example: Setting up crash reporting with Sentry

import * as Sentry from '@sentry/react-native';

Sentry.init({
  dsn: 'YOUR_DSN_HERE',
  tracesSampleRate: 1.0,
});

// Log a crash manually
Sentry.captureException(new Error('Something went wrong'));
Property Description Values
dsn Unique identifier for your project in Sentry string
tracesSampleRate Percentage of transactions to send to Sentry number (0.0 - 1.0)
enableAutoSessionTracking Automatically track session duration true | false
Note: Ensure you have the correct DSN from your Sentry project settings.
Warning: Crash reports may contain sensitive user data. Review and sanitize logs before sending to third-party services.

8. Debugging Production Errors

Example: Setting up Sentry for React Native

// Install Sentry
npm install @sentry/react-native

// Initialize Sentry in your app
import * as Sentry from '@sentry/react-native';

Sentry.init({
  dsn: 'YOUR_DSN_HERE',
  enableAutoSessionTracking: true,
});

// Capture an exception
Sentry.captureException(new Error('Something went wrong'));
Feature Description Notes
Sentry.init() Initializes the Sentry SDK Must be called before any error occurs
captureException() Captures and sends exception to Sentry Can be called with any Error object
captureMessage() Sends a message to Sentry Useful for logging non-exception events
Note: Sentry requires a valid DSN (Data Source Name) to send errors. Make sure to configure it correctly in your production environment.
Warning: Do not send sensitive user data to Sentry. Ensure all PII (Personally Identifiable Information) is stripped before sending.

Example: Custom Error Boundary in React Native

import React from 'react';
import { Alert } from 'react-native';

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo) {
    console.error('Caught an error:', error, errorInfo);
    // Send to crash reporting service
  }

  render() {
    if (this.state.hasError) {
      return (
        <Alert
          title="Something went wrong"
          message="Please restart the app"
        />
      );
    }

    return this.props.children;
  }
}

export default ErrorBoundary;

Best Practices for Production Error Debugging

  • Use a dedicated error reporting service like Sentry or Bugsnag
  • Implement custom error boundaries to gracefully handle crashes
  • Log errors with context (user actions, app state)
  • Filter out sensitive data before sending to error reporting services
  • Set up alerts for critical errors in production

9. Handling Unhandled Exceptions

Exception Type Description Handling Strategy
JavaScript Exceptions Thrown by JavaScript runtime, e.g., TypeError, ReferenceError Use try...catch blocks or global error handlers like errorBoundary
Native Exceptions Thrown by native modules or platform-specific code (iOS/Android) Implement NativeModule error handling or use platform-specific crash reporting tools

Example: Global Error Handler in React Native

import { ErrorUtils } from 'react-native';<br><br>ErrorUtils.setGlobalHandler((error, isFatal) => {<br>  console.log('Global Error:', error);<br>  if (isFatal) {<br>    // Log crash report<br>    console.log('Fatal error occurred');<br>  } else {<br>    // Handle recoverable error<br>    console.log('Recoverable error');<br>  }<br>});
Note: ErrorUtils.setGlobalHandler is a React Native-specific API for catching unhandled JavaScript errors.
Warning: Do not log sensitive user data in global error handlers to avoid privacy issues.

10. Creating Error Fallback UI

Example: Basic Error Boundary Component

import React from 'react';

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo) {
    console.error("Error caught by boundary:", error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      return (
        <div style={{ padding: '20px', backgroundColor: '#ffebee' }}>
          <h2>Something went wrong.</h2>
          <p>We're sorry, but an error occurred.</p>
        </div>
      );
    }

    return this.props.children;
  }
}

export default ErrorBoundary;
Property Description Notes
static getDerivedStateFromError Updates state when an error is thrown in a child component Must return new state or null
componentDidCatch Logs error details for debugging Called after state update; not called for errors in boundary itself
render Controls fallback UI rendering Return null to hide error; return custom UI otherwise
Note: Error boundaries do not catch errors in event handlers, asynchronous code (e.g., setTimeout or requestAnimationFrame), server-side rendering, or errors thrown in the error boundary itself.
Warning: Error boundaries only work for components in the rendering tree below them. They do not catch errors inside themselves or their children's asynchronous operations.

Was this article helpful?