diff --git a/src/common/components/ReloadOnError.jsx b/src/common/components/ReloadOnError.jsx new file mode 100644 index 0000000..cd6ee39 --- /dev/null +++ b/src/common/components/ReloadOnError.jsx @@ -0,0 +1,40 @@ +import { Component } from 'react'; +import PropTypes from 'prop-types'; + +import { NewRelicLoggingService } from '@edx/frontend-logging'; + +/* + Error boundary component used to log caught errors and reload the page. +*/ +export default class ReloadOnError extends Component { + constructor(props) { + super(props); + this.state = { hasError: false }; + } + + static getDerivedStateFromError() { + // Update state so the next render will show the fallback UI. + return { hasError: true }; + } + + componentDidCatch(error, info) { + NewRelicLoggingService.logError(`${error} ${info}`); + } + + render() { + if (this.state.hasError) { + // Reload the page so the user is not stuck with a broken app. + window.location.reload(); + } + + return this.props.children; + } +} + +ReloadOnError.propTypes = { + children: PropTypes.node, +}; + +ReloadOnError.defaultProps = { + children: null, +}; diff --git a/src/common/index.js b/src/common/index.js index 3a23970..1e0f43f 100644 --- a/src/common/index.js +++ b/src/common/index.js @@ -1,9 +1,11 @@ import * as utils from './utils'; import PageLoading from './components/PageLoading'; +import ReloadOnError from './components/ReloadOnError'; import { configureUserAccountApiService, fetchUserAccount } from './actions'; export { PageLoading, + ReloadOnError, utils, configureUserAccountApiService, fetchUserAccount, diff --git a/src/components/App.jsx b/src/components/App.jsx index 121e50d..978f80e 100644 --- a/src/components/App.jsx +++ b/src/components/App.jsx @@ -22,7 +22,7 @@ import { } from '@fortawesome/free-brands-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { fetchUserAccount } from '../common'; +import { ReloadOnError, fetchUserAccount } from '../common'; import { ConnectedProfilePage } from '../profile'; import FooterLogo from '../assets/edx-footer.png'; @@ -212,17 +212,19 @@ class App extends Component { render() { return ( - - - - - - - + + + + + + + + + ); } } diff --git a/src/index.jsx b/src/index.jsx index c327fdc..fd94553 100755 --- a/src/index.jsx +++ b/src/index.jsx @@ -15,24 +15,6 @@ import messages from './i18n'; import './index.scss'; import App from './components/App'; -/* - ARCH-904 - Attempts to protect against browser extension manipulation of the DOM which - causes React to break. See the following link: - https://github.com/facebook/react/issues/11538#issuecomment-417504600 -*/ -if (typeof Node === 'function' && Node.prototype) { - const originalInsertBefore = Node.prototype.insertBefore; - // eslint-disable-next-line func-names - Node.prototype.insertBefore = function (newNode, referenceNode) { - if (referenceNode && referenceNode.parentNode !== this) { - NewRelicLoggingService.logError(`Cannot insert before a reference node from a different parent: ${newNode} ${referenceNode} ${this}`); - return newNode; - } - return originalInsertBefore.apply(this, arguments); // eslint-disable-line prefer-rest-params - }; -} - const apiClient = getAuthenticatedAPIClient({ appBaseUrl: configuration.BASE_URL, authBaseUrl: configuration.LMS_BASE_URL,