Cristian Flórez
Cristian Flórez

Reputation: 2801

How to handle errors globally in react native?

I am not very clear about the process to be able to handle errors globally in a react-native application. How to capture any aplication error and response according to it?, for example show an error screen and a button to 'go home', or run a especific code like retry a request so the user can recover from such an error. which approaches are used in order to handle errors globaly in react-native?

Upvotes: 17

Views: 17933

Answers (1)

shammi
shammi

Reputation: 1419

The error boundaries API only works with class Component, and a class component becomes an error boundary if you define one of these lifecycle methods static getDerivedStateFromError() or componentDidCatch().

React-error-boundary is a simple reusable component based on React error boundary API that provides a wrapper around your components and automatically catch-all error from the children’s components hierarchy, and also provides a great way to recover your component tree.

My suggestion is to wrap every navigation screen in your Application with a react-error-boundary component and provide a fallback component to Make sure the user knows what’s happening, and maybe you can recover the screen with a rerender.

The best way to do it is to create an Errorhandler component like the following.

import * as React from "react";
import { ErrorBoundary } from "react-error-boundary";
import { View, StyleSheet, Button } from "react-native";
import { Text } from "components";
const myErrorHandler = (error: Error) => {
  // Do something with the error
  // E.g. reporting errorr using sentry ( see part 3)
};
function ErrorFallback({ resetErrorBoundary }) {
  return (
    <View style={[styles.container]}>
      <View>
        <Text> Something went wrong: </Text>
        <Button title="try Again" onPress={resetErrorBoundary} />
      </View>
    </View>
  );
}
export const ErrorHandler = ({ children }: { children: React.ReactNode }) => (
  <ErrorBoundary FallbackComponent={ErrorFallback} onError={myErrorHandler}>
    {children}
  </ErrorBoundary>
);
const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: "column",
    alignItems: "stretch",
    justifyContent: "center",
    alignContent: "center",
    paddingHorizontal: 12,
  },
});

As you can see I am using an error fallback component to provide more information to the user instead of a white screen.

I also added a try again button to programmatically re-render the screen as a way to recover it and solve the issue. when the user clicks the try again button the error boundary will trigger a rerender for the Screen Component which can help to avoid error and show the correct components.

Read More about Error Recovery

To mention, I am also wrapping the error boundary component for every component that may throw an error.

Is Error Boundary enough for JS Exceptions? Unfortunately, it’s not, Error boundaries do not catch errors for :

  • Event handlers
  • Asynchronous code (e.g. setTimeout or requestAnimationFrame callbacks)
  • Errors thrown in the error boundary itself (rather than its children)

(Source: Docs)

These limitations lead us to use a react-native-exception-handler to create a global handler for the App that can catch all uncaught Js errors.

react-native-exception-handler is a react native module that lets you register a global error handler that captures fatal/non-fatal uncaught exceptions.

To make it work you need to install and link the module then you register your global handler for Js exception like the following :

import { setJSExceptionHandler } from "react-native-exception-handler";
setJSExceptionHandler((error, isFatal) => {
  // This is your custom global error handler
  // You do stuff like show an error dialog
  // or hit google analytics to track crashes
  // or hit a custom api to inform the dev team.
});

Native Exception As I already mention Native Exceptions were produced from Native modules errors and Internal native react native code.

From my experience, we usually face few uncaught Native exceptions compared to Js ones, the good news is that we are going to use the same library( react-native-exception-handler) to handle native exceptions too but you cannot show a JS alert box or do any UI stuff via JS code. The only solution was to show a native alert provided by the library but native code has to be written in case you want to customize the alert.

To create a global handler for Native exception, you only need to register your handler using setNativeExceptionHandler function like the following :

import { setNativeExceptionHandler } from "react-native-exception-handler";
const exceptionhandler = (exceptionString) => {
  // your exception handler code here
};
setNativeExceptionHandler(
  exceptionhandler,
  forceAppQuit,
  executeDefaultHandler
);

Tracking Exceptions Handling exceptions without tracking them has no sense because all the solutions we discussed only improve the user experience and give more information to the user about the error instead of a white screen or an app crash.

Sentry is a cloud-based error monitoring platform that helps us track all these errors in real-time. By creating a free account and installing react-native-sentry you can use it inside your handler (js and Native) to send the stack errors using captureException like the following:

// ErrorHandler.js
import * as Sentry from "@sentry/react-native";
const myErrorHandler = (error: Error) => {
  Sentry.captureException(error);
};

Now, Make sure to fix your errors.

Upvotes: 21

Related Questions