diff --git a/src/core/plugins/view/root-injects.jsx b/src/core/plugins/view/root-injects.jsx
index 27d4379f..7fdb8fe0 100644
--- a/src/core/plugins/view/root-injects.jsx
+++ b/src/core/plugins/view/root-injects.jsx
@@ -1,4 +1,5 @@
import React, { Component } from "react"
+import PropTypes from "prop-types"
import ReactDOM from "react-dom"
import { connect, Provider } from "react-redux"
import omit from "lodash/omit"
@@ -69,30 +70,71 @@ export const render = (getSystem, getStore, getComponent, getComponents, domNode
ReactDOM.render(( ), domNode)
}
+class ErrorBoundary extends Component {
+ constructor(props) {
+ super(props)
+ this.state = { hasError: false, error: null }
+ }
+
+ static getDerivedStateFromError(error) {
+ return { hasError: true, error }
+ }
+
+ componentDidCatch(error, errorInfo) {
+ console.error(error, errorInfo) // eslint-disable-line no-console
+ }
+
+ render() {
+ if (this.state.hasError) {
+ return
+ }
+
+ return this.props.children
+ }
+}
+ErrorBoundary.propTypes = {
+ targetName: PropTypes.string,
+ children: PropTypes.oneOfType([
+ PropTypes.arrayOf(PropTypes.node),
+ PropTypes.node,
+ ])
+}
+ErrorBoundary.defaultProps = {
+ targetName: "this component",
+ children: null,
+}
+
+const Fallback = ({ name }) => (
+
+ 😱 Could not render { name === "t" ? "this component" : name }, see the console.
+
+)
+Fallback.propTypes = {
+ name: PropTypes.string.isRequired,
+}
+
// Render try/catch wrapper
const createClass = OriginalComponent => class extends Component {
render() {
- return
+ return (
+
+
+
+ )
}
}
-const Fallback = ({
- name // eslint-disable-line react/prop-types
-}) => 😱 Could not render { name === "t" ? "this component" : name }, see the console.
-
const wrapRender = (component) => {
const isStateless = component => !(component.prototype && component.prototype.isReactComponent)
-
const target = isStateless(component) ? createClass(component) : component
-
- const ori = target.prototype.render
+ const { render: oriRender} = target.prototype
target.prototype.render = function render(...args) {
try {
- return ori.apply(this, args)
+ return oriRender.apply(this, args)
} catch (error) {
console.error(error) // eslint-disable-line no-console
- return
+ return
}
}
diff --git a/test/unit/core/system/system.jsx b/test/unit/core/system/system.jsx
index e5082726..43ded037 100644
--- a/test/unit/core/system/system.jsx
+++ b/test/unit/core/system/system.jsx
@@ -1,12 +1,11 @@
-
import React, { PureComponent } from "react"
+import { fromJS } from "immutable"
+import { render, mount } from "enzyme"
+import { Provider } from "react-redux"
import System from "core/system"
-import { fromJS } from "immutable"
-import { render } from "enzyme"
import ViewPlugin from "core/plugins/view/index.js"
import filterPlugin from "core/plugins/filter/index.js"
-import { connect, Provider } from "react-redux"
describe("bound system", function(){
@@ -704,7 +703,7 @@ describe("bound system", function(){
describe("rootInjects", function() {
it("should attach a rootInject function as an instance method", function() {
// This is the same thing as the `afterLoad` tests, but is here for posterity
-
+
// Given
const system = new System({
plugins: [
@@ -985,10 +984,9 @@ describe("bound system", function(){
})
// When
- let Component = system.getSystem().getComponent("BrokenComponent")
- const renderedComponent = render()
+ const Component = system.getSystem().getComponent("BrokenComponent")
+ const renderedComponent = mount()
- // Then
expect(renderedComponent.text().startsWith("😱 Could not render")).toEqual(true)
})