We are exploring the use of Sentry with React.


ITKarma picture


This article is part of a series starting with a Sentry error message using an example: Part 1 .


Implementing React


First we need to add a new Sentry project for this application; from the Sentry website. In this case, we choose React.


We are re-implementing our two buttons, Hello and Error, an application with React. We start by creating our starter app:


npx create-react-app react-app 

Then we import the Sentry package:


yarn add @sentry/browser 

and initialize it:


react-app/src/index.js


... import * as Sentry from '@sentry/browser'; const RELEASE='0.1.0'; if (process.env.NODE_ENV === 'production') { Sentry.init({ dsn: 'https://303c04eac89844b5bfc908ceffc6757c@sentry.io/1289887', release: RELEASE, }); }... 

Observations:


  • During development, we have other mechanisms for monitoring problems, such as the console, so we only enable Sentry for production assemblies

Then we implement our Hello and Error buttons and add them to the application:


react-app/src/Hello.js


import React, { Component } from 'react'; import * as Sentry from '@sentry/browser'; export default class Hello extends Component { state={ text: '', }; render() { const { text }=this.state; return ( <div> <button onClick={this.handleClick} > Hello </button> <div>{text}</div> </div> ) } handleClick=() => { this.setState({ text: 'Hello World', }); try { throw new Error('Caught'); } catch (err) { if (process.env.NODE_ENV !== 'production') { return; } Sentry.captureException(err); } } } 

react-app/src/MyError.js


import React, { Component } from 'react'; export default class MyError extends Component { render() { return ( <div> <button onClick={this.handleClick} > Error </button> </div> ) } handleClick=() => { throw new Error('Uncaught'); } } 

react-app/src/App.js


... import Hello from './Hello'; import MyError from './MyError'; class App extends Component { render() { return ( <div className="App"> ... <Hello/> <MyError/> </div> ); } } export default App; 

Problem (Original Maps)


We can test Sentry with the production assembly by typing:


yarn build 

and from the build folder enter:


npx http-server -c-1 

The problem we will immediately encounter is that the Sentry error entries refer to line numbers in the reduced package; not very helpful.


ITKarma picture


The Sentry service explains this by pulling out the source cards for the reduced package after receiving the error. In this case, we are running from localhost (not accessible by Sentry).


Solutions (Source Cards)


The solution to this problem is to run the application from a public web server. One simple response button for it to use the GitHub Pages service (free). The steps to use are usually the following:


  1. Copy the contents of the build folder to the docs folder in the root directory of the repository.


  2. Include GitHub Pages in the repository (from GitHub) to use the docs folder in the master branch


  3. Paste the changes to GitHub



Note : after I realized that I need to use the create-create-app homepage function to launch the application. It came down to adding the following to package.json:


"homepage": "https://larkintuckerllc.github.io/hello-sentry/" 

The final version of the running application is available at:


https://larkintuckerllc.github.io/hello-sentry/


Illustration of Caught Bugs


Let's go through clicking the Hello button.


ITKarma picture


With an error that appears as follows:


ITKarma picture


Observations:


  • This bug report could not be clearer, BRAVO .

Illustration of Unreported Errors


Similarly, let's go through clicking the Error button.


ITKarma picture


With an error that appears as follows:


ITKarma picture


Better error handling (rendering)


Introducing Error Boundaries

JavaScript error in the part of the user interface should not disrupt the operation of the entire application. To solve this problem for React users, React 16 introduces a new concept of “error margin.”

Error boundaries are React components that catch JavaScript errors anywhere in their child component tree, log these errors, and display a fallback user interface instead of the component tree that crashed. Error boundaries catch errors during rendering, in lifecycle methods, and in the constructors of the entire tree below them.

...

New Behavior for Undetected Errors

This change is important. Starting with React 16, errors that were not caught by any error boundary will result in unmounting the entire React component tree.

- Dan Abramov - Error Handling in React 16

An important clarification that took me some time before I realized this is that the above behavior only works with errors generated in the rendering method (or, more likely, in any of the life methods cycle) . For example, using error borders would not do any good with our Error button; this error was in the click handler.


Let's create an example of a visualization error, and then use the error margins to more elegantly handle the error.


react-app/src/MyRenderError


import React, { Component } from 'react'; export default class MyRenderError extends Component { state={ flag: false, }; render() { const { flag }=this.state; return ( <div> <button onClick={this.handleClick} > Render Error </button> { flag && <div>{flag.busted.bogus}</div> } </div> ) } handleClick=() => { this.setState({ flag: true, }); } } 

Observation:


  • When the button is clicked, React will display flag.busted.bogus , which generates an error


  • Without an error boundary, the entire component tree will be unmounted



Then we write our error boundary code (uses the new life cycle method componentDidCatch ); this, in fact, is an example cited in an article by Dan Abramov:


react-app/src/ErrorBoundary.js


import React, { Component } from 'react'; import * as Sentry from '@sentry/browser'; export default class ErrorBoundary extends Component { constructor(props) { super(props); this.state={ hasError: false }; } componentDidCatch(err, info) { this.setState({ hasError: true }); Sentry.captureException(err); } render() { if (this.state.hasError) { return <h1>Something went wrong.</h1>; } return this.props.children; } } 

Finally, we use this component:


react-app/src/App.js


... import MyRenderError from './MyRenderError'; class App extends Component { render() { return ( <ErrorBoundary> <div className="App"> ... </div> </ErrorBoundary> ); } }... 

At the same time, pressing the Render Error button displays the backup user interface and reports a Sentry error.


ITKarma picture


ITKarma picture


Finishing


I hope you find this helpful.


P.S. Link to the original


P.S. Telegram chat by Sentry https://t.me/sentry_ru

.

Source