Preface No one is perfect, so there will always be errors in the code. Errors are not terrible, the key is how to deal with them.
ErrorBoundary EerrorBoundary came out in version 16. Someone asked me what about my version 15. I didn’t want to hear it. I use version 16 anyway, and of course 15 has The official website of ErrorBoundary has a detailed introduction, but this is not the point. The point is what exceptions it can capture.
constructor(props) { super(props); this.state = { hasError: false }; } componentDidCatch(error, info) { // Display fallback UI this.setState({ hasError: true }); // You can also log the error to an error reporting service logErrorToMyService(error, info); } render() { if (this.state.hasError) { // You can render any custom fallback UI return <h1>Something went wrong.</h1>; } return this.props.children; } } <ErrorBoundary> <MyWidget /> </ErrorBoundary> The open source world is great. A great author has already encapsulated an excellent library like react-error-boundary. import {ErrorBoundary} from 'react-error-boundary' function ErrorFallback({error, resetErrorBoundary}) { return ( <div role="alert"> <p>Something went wrong:</p> <pre>{error.message}</pre> <button onClick={resetErrorBoundary}>Try again</button> </div> ) } const ui = ( <ErrorBoundary FallbackComponent={ErrorFallback} onReset={() => { // reset the state of your app so the error doesn't happen again }} > <ComponentThatMayError /> </ErrorBoundary> ) Unfortunately, error boundaries do not catch these errors:
The original text can be found at the official website introducing-error-boundaries This article aims to capture errors in event handlers. But, so many event handlers, my God, how many do I have to write? . . . . . . . . . . . . . . . . . . . handleClick() { try { // Do something that could throw } catch (error) { this.setState({ error }); } } Beyond Error BoundaryLet's first look at a table that lists the means and scope by which we can capture exceptions.
try/catch Can catch both synchronous and async/await exceptions. window.onerror , error eventwindow.addEventListener('error', this.onError, true); window.onerror = this.onError window.addEventListener('error') can capture more resources and record exceptions than window.onerror. unhandledrejection Note that the last parameter is true. window.removeEventListener('unhandledrejection', this.onReject, true) It catches uncaught Promise exceptions. XMLHttpRequest and fetch XMLHttpRequest is easy to handle and has its own onerror event. ErrorBoundary.prototype.componentDidMount = function () { // event catch window.addEventListener('error', this.catchError, true); // async code window.addEventListener('unhandledrejection', this.catchRejectEvent, true); }; use: import ErrorCatch from 'react-error-catch' const App = () => { return ( <ErrorCatch app="react-catch" user="cxyuns" delay={5000} max={1} filters={[]} onCatch={(errors) => { console.log('error reported'); // Report exception information to the backend and dynamically create tags new Image().src = `http://localhost:3000/log/report?info=${JSON.stringify(errors)}` }} > <Main /> </ErrorCatch>) } export default Applause, applause. Exception catching in event handlers Example My idea is very simple, use decorator to rewrite the original method. @methodCatch({ message: "Failed to create order", toast: true, report:true, log:true }) async createOrder() { const data = {...}; const res = await createOrder(); if (!res || res.errCode !== 0) { return Toast.error("Failed to create order"); } ....... Other codes that may cause exceptions... Toast.success("Order created successfully"); } Note the four parameters:
Maybe you will say that this is news that is certain and unreasonable. What if I had any other news? @methodCatch({ message: "Failed to create order", toast: true, report:true, log:true }) async createOrder() { const data = {...}; const res = await createOrder(); if (!res || res.errCode !== 0) { return Toast.error("Failed to create order"); } ....... Other codes that may cause exceptions... throw new CatchError("Failed to create order, please contact the administrator", { toast: true, report: true, log: false }) Toast.success("Order created successfully"); } Yes, that’s right, you can override the default options by throwing a custom CatchError. Type Definitionexport interface CatchOptions { report?: boolean; message?: string; log?: boolean; toast?: boolean; } // It is more reasonable to write it in const.ts export const DEFAULT_ERROR_CATCH_OPTIONS: CatchOptions = { report: true, message: "Unknown exception", log: true, toast: false } Custom CatchErrorimport { CatchOptions, DEFAULT_ERROR_CATCH_OPTIONS } from "@typess/errorCatch"; export class CatchError extends Error { public __type__ = "__CATCH_ERROR__"; /** * Caught error * @param message message * @options other parameters */ constructor(message: string, public options: CatchOptions = DEFAULT_ERROR_CATCH_OPTIONS) { super(message); } } Decoratorsimport Toast from "@components/Toast"; import { CatchOptions, DEFAULT_ERROR_CATCH_OPTIONS } from "@typess/errorCatch"; import { CatchError } from "@util/error/CatchError"; const W_TYPES = ["string", "object"]; export function methodCatch(options: string | CatchOptions = DEFAULT_ERROR_CATCH_OPTIONS) { const type = typeof options; let opt : CatchOptions; if (options == null || !W_TYPES.includes(type)) { // null or not a string or object opt = DEFAULT_ERROR_CATCH_OPTIONS; } else if (typeof options === "string") { // string opt = { ...DEFAULT_ERROR_CATCH_OPTIONS, message: options || DEFAULT_ERROR_CATCH_OPTIONS.message, } } else { // Valid object opt = { ...DEFAULT_ERROR_CATCH_OPTIONS, ...options } } return function (_target: any, _name: string, descriptor: PropertyDescriptor): any { const oldFn = descriptor.value; Object.defineProperty(descriptor, "value", { get() { async function proxy(...args: any[]) { try { const res = await oldFn.apply(this, args); return res; } catch (err) { // if (err instanceof CatchError) { if(err.__type__ == "__CATCH_ERROR__"){ err = err as CatchError; const mOpt = { ...opt, ...(err.options || {}) }; if (mOpt.log) { console.error("asyncMethodCatch:", mOpt.message || err.message , err); } if (mOpt.report) { // TODO:: } if (mOpt.toast) { Toast.error(mOpt.message); } } else { const message = err.message || opt.message; console.error("asyncMethodCatch:", message, err); if (opt.toast) { Toast.error(message); } } } } proxy._bound = true; return proxy; } }) return descriptor; } } To sum upUse decorators to rewrite the original method to capture errors. Customize the error class and throw it to override the default options. Increased flexibility. @methodCatch({ message: "Failed to create order", toast: true, report:true, log:true }) async createOrder() { const data = {...}; const res = await createOrder(); if (!res || res.errCode !== 0) { return Toast.error("Failed to create order"); } Toast.success("Order created successfully"); ....... Other codes that may cause exceptions... throw new CatchError("Failed to create order, please contact the administrator", { toast: true, report: true, log: false }) } Next step What’s the next step? Let’s take it one step at a time. Expanding results @XXXCatch class AAA{ @YYYCatch method = () => { } } Abstract, abstract, abstract goodbye. Final Thoughts error-boundaries This is the end of this article about how to capture exceptions in React elegantly. For more content about React catching exceptions, please search for previous articles on 123WORDPRESS.COM or continue to browse the following related articles. I hope you will support 123WORDPRESS.COM in the future! You may also be interested in:
|
<<: MySQL database migration quickly exports and imports large amounts of data
Table of contents 1. Using Set()+Array.from() 2. ...
1. Add a new user Only allow local IP access crea...
When there are tens of thousands of records in th...
background Some time ago, our project team was he...
This article shares the specific code of the js n...
Preface: As far as I know, currently CSS can only...
Table of contents Introduction Traditional transi...
1. Pull the image First, execute the following co...
I recently wanted to convert a website to https a...
1. Download the image docker pull selenium/hub do...
Table of contents Overview Blob Blob in Action Bl...
The reason is simple: In HTML documents, multiple ...
1. Install MySQL database on mac 1. Download MySQ...
Body part: <button>Turn on/off light</bu...
Table of contents 01 Container consistency 02 Con...