Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Advanced React] Error Handling #100

Open
reboottime opened this issue May 23, 2024 · 4 comments
Open

[Advanced React] Error Handling #100

reboottime opened this issue May 23, 2024 · 4 comments

Comments

@reboottime
Copy link
Owner

reboottime commented May 23, 2024

Overview

This article is a reading note of the error handling chapter from <<Advanced React>>, together with some of my practices.


Best Practices

@reboottime
Copy link
Owner Author

reboottime commented May 23, 2024

Novice Level Tips

  • Apply try catch to your javascript code
  • Do not setState during the rendering process
  • have proper error handling at your axios interceptor
    • do not forget catch up network disconnection error,

image

@reboottime
Copy link
Owner Author

reboottime commented May 23, 2024

Production Levels Tips

Error Management User Experience

The errors component of usability considers how well a product or system handles user mistakes. It involves designing error prevention mechanisms and providing clear error messages or recovery paths when mistakes occur. The goal is to minimize user errors and make error recovery straightforward.



Error on visiting Page

  • Not Found page for a resource
  • No Access Page, in practice, we render UI as not found page for security consideration
  • Not Found page


Error that caught by ErrorBoundary

  • First, try to prevent users from having that error

  • If error happens

    • log the error to logging system
    • Provide Proper UI to the Error
      • describe what happened
      • how to recover from error
        • maybe retry a few minutes later
        • maybe contact customer support services
  • Example UI Design

  • Code sample

The widely used solution is react-error-boundary. Bellow is a sample code

import { ErrorBoundary, type FallbackProps } from 'react-error-boundary';

// some other code

<ErrorBoundary
  fallbackRender={(props) => <ErrorFallback {...props} />}
  onError={(error) => {
    /*
     log error to the server here
    */
  }}
>
  <Suspense fallback={<Loading />}>
    <Outlet />
  </Suspense>
</ErrorBoundary>

@reboottime
Copy link
Owner Author

reboottime commented May 23, 2024

Handle Axios Error

The best practices of applying axios have been covered in other articles. Specially, in this section, we talk about error handling. Bellow is my design

  • declare http client error
export class HttpError extends Error {
  cause: string;

  static RESOURCE_NOT_FOUND = 'RESOURCE_NOT_FOUND';
  static TIMEOUT = 'TIMEOUT';
  static NETWORK_ERROR = 'NETWORK_ERROR';
  static SERVICE_UNAVAILABLE = 'SERVICE_UNAVAILABLE';

  constructor(message: string, cause: string) {
    super(message);
    this.cause = cause;
  }
}
  • Return corresponding error at axios instance interceptor
this.clientInstance.interceptors.response.use(
  (res) => res.data,
  (error: AxiosError<BackendError>) => {
    if (!error) {
      return Promise.reject(new Error('Unknown error occurred.'));
    }

    if (error.code === 'ECONNABORTED') {
      return Promise.reject(
        new HttpError('Request timed out.', HttpError.TIMEOUT)
      );
    }

    if (error.code === 'ERR_NETWORK') {
      return Promise.reject(
        new HttpError(
          'Network error occurred. Please check your internet connection.',
          HttpError.NETWORK_ERROR
        )
      );
    }

    if (error.response && error.response.status >= 500) {
      return Promise.reject(
        new HttpError(
          'Service unavailable. Please try again later or contact support.',
          HttpError.SERVICE_UNAVAILABLE
        )
      );
    }

    if (error.response && error.response.status === 404) {
      return Promise.reject(
        new HttpError('Resource not found.', HttpError.RESOURCE_NOT_FOUND)
      );
    }

    const { message: axiosMessage, response } = error;
    const { status, data } = response ?? {};

    let errorMessage = axiosMessage;

    if (status === 401) {
      HttpClient.removeAccessToken();
      toast.error('Your session has expired. Please log in again.');

      setTimeout(() => {
        window.location.reload();
      }, 2500);

      return;
    }

    errorMessage = data?.message ?? axiosMessage ?? 'Unknown Error.';

    return Promise.reject(new Error(errorMessage));
  }
);

// The eror data format designed with backend
interface BackendError {

}

Designed logic as above, as there are cases we want to handle 500, 403, 404 error not in a general way in my application case.

@reboottime
Copy link
Owner Author

reboottime commented May 24, 2024

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant