Monday, April 29, 2024
HomeRuby On RailsA Information to Dealing with Errors in Preact

A Information to Dealing with Errors in Preact


To err is human. It occurs on a regular basis. If we don’t account for errors on our web sites, then our customers will get an terrible shopping expertise. That’s why it’s higher to plan for errors.

In at present’s submit, we’ll undergo alternative ways of dealing with errors in Preact purposes.

Let’s get going!

Catching Rendering Errors in Preact

Since Preact is a light-weight React different, comparable guidelines to the React world additionally apply right here. You may’t use the traditional strive...catch methodology of resolving errors whereas rendering as a result of it’s meant to deal with crucial code.

However what’s a typical rendering error, you’re most likely asking? Think about a part like this:

import { h } from "preact"

const CrashableComponent = (props) => {
  return <>{props.iDontExist.meNeither}</>
}

export default CrashableComponent

Making an attempt to render CrashableComponent by itself will break the web page, leaving the consumer stranded. We additionally get an error within the browser console like this one:



Rendering error

So the traditional strive...catch methodology gained’t do us any good right here. What’s going to do the job and make sure the web page remains to be usable when an error like this occurs? To correctly deal with rendering errors in Preact, you should utilize these two approaches:

  1. componendDidCatch
  2. useErrorBoundary hook

We’ll undergo each within the following sections.

1. Catch Rendering Errors Utilizing componentDidCatch

One strategy to deal with errors is to create a category part that implements the componentDidCatch lifecycle methodology. It may possibly look one thing like this:

import { h, Element } from "preact"

class Catcher extends Element {
  constructor() {
    tremendous()
    this.state = { errored: false, error: null }
  }

  componentDidCatch(error) {
    this.setState({ errored: true, error })
  }

  render(props, state) {
    if (state.errored) {
      return (
        <>
          <h1>Oh no! I'm a Catcher</h1>
          <p>Pay attention up, one thing went badly mistaken 😭</p>
          <p>This is the error message: {state.error.message}</p>
        </>
      )
    }

    return props.youngsters
  }
}

export default Catcher

Then, we have to wrap our problematic part (or parts) with the Catcher part, like so:

<Catcher>
  <CrashableComponent />
</Catcher>

Now, once we render the web page, it would work and present the fallback code we outlined within the Catcher part:



Caught error with class component

Error dealing with utilizing componentDidCatch will work for any error within the youngster parts. Some of us use a worldwide error catcher that wraps many of the software as a root or near-root part.

What’s nice about this method is which you could write any logic you need in componentDidCatch. It’s a good suggestion to push the error to an error-tracking service like AppSignal. Right here’s an instance:

componentDidCatch(error) {
  appsignal.sendError(error)
}

Now let’s see how we are able to deal with rendering errors in Preact with the useErrorBoundary hook.

2. useErrorBoundary Hook to Catch Rendering Errors

Preact exports a hook you should utilize to catch and simply retry an error. The hook is named useErrorBoundary, and might go inside a part:

const [error, resetError] = useErrorBoundary()

To raised illustrate this, let’s create a purposeful part in Preact that handles errors for us:

import { h } from "preact"
import { useErrorBoundary } from "preact/hooks"

const CatcherWithHook = (props) => {
  const [error, resetError] = useErrorBoundary()

  if (error) {
    return (
      <>
        <h1>Oh no! I'm a CatcherWithHook</h1>
        <p>One thing went badly mistaken and useErrorBoundary was used 😭</p>
        <p>This is the error message: {error.message}</p>

        <button onClick={resetError}>Attempt once more</button>
      </>
    )
  }

  return props.youngsters
}

export default CatcherWithHook

We get the CatcherWithHook part, which is leaner than the unique Catcher with the componentDidCatch implementation. Additionally, utilizing the useErrorBoundary is extra handy as a result of it takes care of the resetError half for you. With componentDidCatch, you need to care for and reset the state manually.

To verify errors are caught, we have to wrap the problematic code with the brand new part we’ve made:

<CatcherWithHook>
  <CrashableComponent />
</CatcherWithHook>

Now, once we render the web page, it would present a fallback message and a button to retry the rendering, like so:



Caught error with a functional component and a hook in Preact

The identical rule applies right here — any rendering error in a baby part of CatcherWithHook will probably be caught, and a fallback UI will probably be proven.

An necessary factor to notice is which you could leverage an non-obligatory callback for monitoring functions and move that as the primary argument to useErrorBoundary. So if you wish to report the error to a service like AppSignal, right here’s the way to do it:

const [error] = useErrorBoundary((error) => appsignal.sendError(error))

Superior – we lined all of Preact’s options for dealing with errors! However we have now to remember that componentDidCatch and useErrorBoundary gained’t catch all errors. They don’t catch errors for:

  • Occasion handlers
  • Asynchronous code (e.g., setTimeout or requestAnimationFrame callbacks)
  • Errors which are thrown within the error boundary itself (fairly than its youngsters)

You continue to want to make use of the strive...catch assertion for these circumstances. So let’s go forward and present how you are able to do that.

Preact Error Catching in Occasion Handlers

As talked about earlier than, instruments like componentDidCatch and useErrorBoundary can’t assist us with errors in occasion handlers. For these situations, we must always return to the old style strive...catch block:

import { h } from "preact"
import { useState } from "preact/hooks"

const CrashIfClicked = () => {
  const [error, setError] = useState(null)

  if (error) {
    return (
      <>
        <p>An error occurred, sorry!</p>
        <button onClick={() => setError(null)}>Attempt once more</button>
      </>
    )
  }

  return (
    <>
      <p>This can be a part that may crash the app.</p>

      <button
        onClick={() => {
          strive {
            throw new Error("Crash!")
          } catch (e) {
            setError(e)
          }
        }}
      >
        Crash!
      </button>
    </>
  )
}

export default CrashIfClicked

If we attempt to render this crashable button and work together with it, it will occur:

Handling errors in event handlers

An analogous factor occurs with errors in setTimeout calls.

Error Catching in setTimeout Calls

Think about an identical part, but it surely has a setTimeout name within the occasion handler. Right here it’s:

import { h } from "preact"
import { useState } from "preact/hooks"

const CrashAfterAWhile = () => {
  const [error, setError] = useState(null)

  if (error) {
    return (
      <>
        <p>An error occurred, sorry!</p>
        <button onClick={() => setError(null)}>Attempt once more</button>
      </>
    )
  }

  return (
    <>
      <p>
        This can be a part that may crash after 1 second inside clicking the
        button.
      </p>

      <button
        onClick={() => {
          setTimeout(() => {
            strive {
              throw new Error("I crashed after 1 second!")
            } catch (e) {
              setError(e)
            }
          }, 1000)
        }}
      >
        Crash after 1 second!
      </button>
    </>
  )
}

export default CrashAfterAWhile

Once we work together with the button, it would throw an error after 1000 milliseconds. Then, we’ll catch the error and present a fallback message. Right here’s the way it seems:

Handling errors in setTimeout call

That’s good and dandy! Our app is catching errors and displaying messages and retry buttons to our customers as a substitute of clean screens.

There’s additionally one different strategy to deal with errors — by utilizing AppSignal’s Preact integration.

Monitoring Errors in Preact with AppSignal

AppSignal has a @appsignal/preact bundle that requires Preact 10.0.0 or greater. You may add it to your undertaking with these instructions:

yarn add @appsignal/javascript @appsignal/preact
npm set up --save @appsignal/javascript @appsignal/preact

Then within the code, you should utilize the ErrorBoundary offered by @appsignal/preact like so:

import { h, Element } from "preact"
import Appsignal from "@appsignal/javascript"

import { ErrorBoundary } from "@appsignal/preact"

export const appsignal = new Appsignal({
  key: "YOUR FRONTEND API KEY",
})

const FallbackComponent = ({ error }) => (
  <>
    <p>Uh oh! There was an error caught by AppSignal's ErrorBoundary :(</p>
    <p>This is the error: {error.message}</p>
  </>
)

class AppSignalCatcher extends Element {
  render(props) {
    return (
      <ErrorBoundary
        occasion={appsignal}
        tags={{ tag: "worth" }}
        fallback={(error) => <FallbackComponent error={error} />}
      >
        {props.youngsters}
      </ErrorBoundary>
    )
  }
}

export default AppSignalCatcher

To verify errors are caught, we have to wrap the kid parts with the brand new part we’ve made:

<AppSignalCatcher>
  <CrashableComponent />
</AppSignalCatcher>

Then we must always see the fallback errors message in our app like so:



AppSignal's ErrorBoundary caught an error

Right here’s an instance of how this error seems in AppSignal:

Preact error message on AppSignal

Utilizing ErrorBoundary offered by AppSignal is nice as a result of you’ll be able to:

  • Catch rendering errors
  • Present fallback UI for customers
  • Report any mishaps to AppSignal to allow them to be tracked

Wrapping Up

Thanks for studying this weblog submit about dealing with errors in Preact.
Thanks for studying this weblog submit about dealing with errors in Preact. Try this GitHub repo for all of the code, with examples.

In abstract, Preact options just like the componentDidCatch lifecycle methodology and useReactBoundary hook are nice for catching errors in declarative code (e.g., inside their youngster part tree).

For different circumstances, you must use a strive...catch assertion (e.g., async calls like setTimeout, occasion handlers, and errors thrown within the error boundary itself).

That’s all, of us. Thanks for studying, and catch you within the subsequent one!

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments