Skip to content

Instantly share code, notes, and snippets.

@pesterhazy
Last active October 12, 2021 00:19
Show Gist options
  • Save pesterhazy/d163a8b3f1f1c6a0dac235858776c14b to your computer and use it in GitHub Desktop.
Save pesterhazy/d163a8b3f1f1c6a0dac235858776c14b to your computer and use it in GitHub Desktop.
Reagent error boundary for recovering from exceptions
(ns error-boundary.error-boundary
(:require [reagent.core :as r]
[reagent.impl.component :as comp]
[reagent.impl.util :as util]
[goog.object :as gobj]))
;; (c) 2016 Paulus Esterhazy
;;
;; License: MIT
;; Store in a file called error_boundary/error_boundary.cljs in your classpath.
;;
;; Tested with reagent 0.6.0
;;
;; See
;;
;; https://github.com/reagent-project/reagent/issues/272
;;
;; https://github.com/facebook/react/blob/15-stable/src/renderers/shared/stack/reconciler/__tests__/ReactErrorBoundaries-test.js
;;
;; https://github.com/facebook/react/issues/2461
(def error-boundary
"Wrapper component for recovering from exceptions in downstream
render fns. Creates an error boundary that prevents exceptions from corrupting
the React component hierarchy.
Use this component to wrap a single reagent (root) component. Any exception
thrown in downstream render fns will be caught and logged. The component's
child and its children will not be rendered.
This is useful in a reloading-based development workflow.
Example usage:
(ns my-ns
(:require [error-boundary.error-boundary :refer [error-boundary]]))
(r/render-component (fn [] [error-boundary [root]])
(.. js/document (querySelector \"#container\")))
Note that this relies on the undocumented unstable_handleError API introduced
in React 15.
This componenet may have performance implications, so it is recommended to
enable it only during development."
(r/adapt-react-class (comp/create-class
{:getInitialState
(fn []
#js {:error false})
:unstable_handleError
(fn [e]
(this-as this
(if (ex-data e)
(js/console.error (pr-str e))
(js/console.error e))
(.setState this #js {:error true})))
:render
(fn []
(this-as this
(let [children (.. util/react
-Children
(toArray (.. this -props -children)))]
(when (not= 1 (count children))
(js/console.warn "Component error-boundary requires a single child component. Additional children are ignored."))
(if (gobj/get (.. this -state) "error")
(do
(js/console.warn "An error occurred downstream (see errors above). The element subtree will not be rendered.")
nil)
(first children)))))})))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment